SlideShare a Scribd company logo
Writeup​ ​CTF​ ​Online​ ​IDSECCONF​ ​2017
Visat
Misc 1
Dungeon​ ​(100​ ​pts) 1
Reverse 3
Logang​ ​(20​ ​pts) 3
Darwin​ ​(100​ ​pts) 3
Whoami​ ​(400​ ​pts) 7
Misc
Dungeon​ ​(100​ ​pts)
Diberikan​ ​sebuah​ ​​web​ ​service​​ ​yang​ ​mempunyai​ ​labirin​ ​seperti​ ​pada​ ​gambar.
1
Misi kita adalah memberikan arah jalan dari P menuju E. Hal ini dapat dilakukan dengan
algoritma​ ​BFS.​ ​Buat​ ​​script​​ ​untuk​ ​melakukannya​ ​secara​ ​otomatis.
#!/usr/bin/env​​python 
 
from​​pwn​​import​​* 
 
dr​​=​​[0,1,0,-1] 
dc​​=​​[1,0,-1,0] 
dd​​=​​['R',​​'D',​​'L',​​'U'] 
 
def​​bfs(maze,​​rowc,​​colc): 
​​​​​​​​queue​​=​​[(rowc,​​colc,​​[])] 
​​​​​​​​visited​​=​​set() 
​​​​​​​​while​​queue: 
  ​​r,c,l​​=​​queue.pop(0) 
  ​​visited.add((r,c)) 
  ​​for​​k​​in​​range(4): 
  ​​row​​=​​r+dr[k] 
  ​​col​​=​​c+dc[k] 
  ​​if​​row​​<​​0​​or​​row​​>=​​len(maze): 
  ​​continue 
  ​​if​​col​​<​​0​​or​​col​​>=​​len(maze[0]): 
  ​​continue 
  ​​if​​maze[row][col]​​==​​'E': 
  ​​return​​l​​+​​[dd[k]] 
  ​​if​​maze[row][col]​​!=​​'​​': 
  ​​continue 
  ​​if​​(row,col)​​in​​visited: 
  ​​continue 
  ​​queue.append((row,col,l+[dd[k]])) 
 
r​​=​​remote('62.4.3.98',​​10111) 
print​​r.recvuntil("start") 
r.recvline() 
r.sendline("") 
 
while​​1: 
​​​​​​​​s​​=​​r.recvline() 
​​​​​​​​print​​s 
​​​​​​​​if​​"flag"​​in​​s: 
  ​​print​​s 
  ​​break 
​​​​​​​​s​​=​​r.recvline() 
​​​​​​​​s​​=​​s.split() 
​​​​​​​​row​​=​​int(s[-1].strip()) 
 
​​​​​​​​s​​=​​r.recvline() 
​​​​​​​​s​​=​​s.split() 
​​​​​​​​col​​=​​int(s[-1].strip()) 
 
​​​​​​​​print​​row,col 
2
 
​​​​​​​​maze​​=​​[] 
​​​​​​​​for​​i​​in​​range(row): 
  ​​s​​=​​r.recvline().strip() 
  ​​maze.append(s) 
 
  ​​if​​'P'​​in​​s: 
  ​​rowc​​=​​i 
  ​​colc​​=​​s.index('P') 
 
​​​​​​​​for​​c​​in​​bfs(maze,rowc,colc): 
  ​​print​​r.recvline(), 
  ​​r.recvline() 
  ​​r.sendline(c) 
 
​​​​​​​​s​​=​​r.recvline() 
​​​​​​​​if​​"flag"​​in​​s: 
  ​​print​​s 
  ​​break 
​​​​​​​​r.sendline("") 
Setelah​ ​maze​ ​ke-10,​ ​didapatkan​ ​flag.
Flag:​ ​​flag{pOwer_pOLe_paPAh} 
Reverse
Logang​ ​(20​ ​pts)
Diberikan sebuah ​binary ELF 32-bit yang menggunakan bahasa Go. Langkah pertama dalam
reversing​​ ​biasanya​ ​adalah​ ​mencari​ ​flag​ ​dengan​ ​menggunakan​ ​command​ ​​strings​​ ​dan​ ​​grep​.
$​​strings​​logang​​|​​grep​​-iE​​"^[a-zA-Z0-9_{}]*$"​​|​​less 
Terdapat string menarik, yaitu ​flag{​, ​go_rEverse​, dan ​_aLa_pApah}​. Jika digabungkan
akan​ ​didapatkan​ ​flag.
Flag:​ ​​flag{go_rEverse_aLa_pApah}
Darwin​ ​(100​ ​pts)
Diberikan sebuah ​binary Mach-O 32 bit. Setelah melakukan ​decompile dengan IDA Pro,
pseudocode​-nya​ ​adalah​ ​sebagai​ ​berikut.
3
signed​​int​​start()​​{ 
​​​​​​​​memset(v3,​​0,​​0x20u); 
​​​​​​​​printf("Enter​​the​​key​​:​​"); 
​​​​​​​​v2​​=​​0; 
​​​​​​​​fgets(v3,​​32,​​__stdinp); 
​​​​​​​​while​​(​​v2​​<​​32​​)​​{ 
  ​​v0​​=​​0; 
  ​​if​​(​​v3[v2]​​==​​10​​) 
  ​​v0​​=​​-10; 
  ​​v3[v2++]​​+=​​v0; 
​​​​​​​​} 
​​​​​​​​if​​(​​sub_1A30(v3)​​) 
  ​​printf("Congratz,​​the​​flag​​:nflag{yOu_%s_3v3r}n",​​v3); 
​​​​​​​​else 
  ​​printf("Wrong​​%s​​not​​the​​key.n",​​v3); 
} 
Program meminta masukan ​key​, lalu dilakukan pengecekan dengan fungsi ​sub_1A30​. Jika
fungsi​ ​bernilai​ ​​true​,​ ​maka​ ​flag-nya​ ​adalah​ ​​flag{yOu_<key>_3v3r}​.
bool​​sub_1A30(char​​*a1)​​{ 
​​​​​​​​v18​​=​​strlen(a1); 
​​​​​​​​v17​​=​​0; 
​​​​​​​​v16​​=​​0; 
​​​​​​​​v15​​=​​0; 
​​​​​​​​v14​​=​​0; 
​​​​​​​​v13​​=​​0; 
​​​​​​​​v12​​=​​0; 
   
​​​​​​​​for​​(​​i​​=​​0;​​i​​<​​v18;​​++i​​)​​{ 
  ​​if​​(​​i​​%​​2​​) 
  ​​v7​​=​​*(a1​​+​​i)​​^​​v14; 
  ​​else 
  ​​v7​​=​​v14; 
  ​​v14​​=​​v7; 
  ​​if​​(​​i​​%​​2​​==​​1​​) 
  ​​v6​​=​​v13; 
  ​​else 
  ​​v6​​=​​*(a1​​+​​i)​​^​​v13; 
  ​​v13​​=​​v6; 
  ​​if​​(​​i​​%​​2​​) 
  ​​v5​​=​​0; 
  ​​else 
  ​​v5​​=​​*(a1​​+​​i); 
  ​​v17​​+=​​v5; 
  ​​if​​(​​i​​%​​2​​==​​1​​) 
  ​​v4​​=​​*(a1​​+​​i)​​^​​v15; 
  ​​else 
  ​​v4​​=​​v15; 
  ​​v15​​=​​v4; 
​​​​​​​​} 
4
   
​​​​​​​​for​​(​​j​​=​​0;​​j​​<​​v18​​/​​2;​​++j​​) 
  ​​v12​​^=​​*(a1​​+​​j); 
   
​​​​​​​​for​​(​​k​​=​​0;​​k​​<​​v18;​​++k​​)​​{ 
  ​​if​​(​​k​​%​​2​​) 
  ​​v3​​=​​*(a1​​+​​k); 
  ​​else 
  ​​v3​​=​​0; 
  ​​v16​​+=​​v3; 
  ​​if​​(​​k​​%​​2​​) 
  ​​v2​​=​​v15; 
  ​​else 
  ​​v2​​=​​*(a1​​+​​k)​​^​​v15; 
  ​​v15​​=​​v2; 
​​​​​​​​} 
 
​​​​​​​​v11​​=​​sub_19C0(a1); 
​​​​​​​​return​​v17​​%​​10​​==​​8 
  ​​&&​​v16​​%​​10​​==​​v17​​%​​10 
  ​​&&​​v18​​==​​13 
  ​​&&​​v15​​==​​90 
  ​​&&​​v12​​==​​21 
  ​​&&​​v14​​==​​56 
  ​​&&​​(v16​​+​​v17)​​/​​10​​==​​116 
  ​​&&​​(v16​​+​​2​​*​​v17)​​/​​10​​==​​183 
    ​​&&​​*(a1​​+​​1)​​==​​'3' 
  ​​&&​​*(a1​​+​​5)​​==​​'5' 
  ​​&&​​*(a1​​+​​8)​​==​​'4' 
  ​​&&​​*(a1​​+​​10)​​==​​'7' 
  ​​&&​​v11​​==​​0xFD4E6A44; 
} 
 
int​​sub_19C0(const​​char​​*a1)​​{ 
​​​​​​​​v4​​=​​strlen(a1); 
​​​​​​​​v3​​=​​23; 
​​​​​​​​for​​(​​i​​=​​0;​​i​​<​​v4;​​++i​​) 
  ​​v3​​=​​(a1[i]​​<<​​i)​​+​​7​​*​​v3; 
​​​​​​​​return​​v3​​>>​​4; 
} 
Terdapat beberapa kondisi yang harus dipenuhi beberapa variabel agar fungsi tersebut bernilai
true​.​ ​Evaluasi​ ​dari​ ​variabel​ ​tersebut​ ​adalah​ ​sebagai​ ​berikut:
● v18​​ ​adalah​ ​panjang​ ​​key​.
● v17​​ ​adalah​ ​penjumlahan​ ​dari​ ​karakter​ ​​key​​ ​berindeks​ ​genap.
● v16​​ ​adalah​ ​penjumlahan​ ​dari​ ​karakter​ ​​key​​ ​berindeks​ ​ganjil.
● v15​​ ​adalah​ ​hasil​ ​xor​ ​semua​ ​karakter​ ​​key​.
● v14​​ ​adalah​ ​hasil​ ​xor​ ​semua​ ​karakter​ ​​key​​ ​berindeks​ ​ganjil.
● v12​​ ​adalah​ ​hasil​ ​xor​ ​karakter​ ​dari​ ​​0​​ ​sampai​ ​​len(key)//2​.
● v11​​ ​adalah​ ​hasil​ ​fungsi​ ​​sub_19c0 
5
Terdapat beberapa kondisi yang harus dipenuhi variabel tersebut, yang akan kita sebut
constraint​. Permasalahan ​constraint seperti ini dapat dicari solusinya dengan cepat dengan
menggunakan​ ​Z3.​ ​Solver​ ​script​ ​untuk​ ​​constraint​​ ​ini​ ​adalah​ ​sebagai​ ​berikut.
#!/usr/bin/env​​python3 
 
from​​z3​​import​​* 
import​​string 
import​​itertools 
 
length​​=​​13 
X​​=​​[BitVec('x%s'​​%​​i,​​32)​​for​​i​​in​​range(length)] 
s​​=​​Solver() 
 
#​​charset​​constraint,​​letters​​+​​digits​​+​​underscore 
for​​i​​in​​range(len(X)): 
​​​​​​​​s.add(Or( 
  ​​And(X[i]​​>=​​ord('A'),​​X[i]​​<=​​ord('Z')), 
  ​​And(X[i]​​>=​​ord('a'),​​X[i]​​<=​​ord('z')), 
  ​​And(X[i]​​>=​​ord('0'),​​X[i]​​<=​​ord('9')), 
  ​​X[i]​​==​​ord('_') 
​​​​​​​​)) 
 
xor_half​​=​​X[0] 
for​​i​​in​​range(1,​​len(X)​​//​​2): 
​​​​​​​​xor_half​​^=​​X[i] 
 
xor_even​​=​​X[0] 
add_even​​=​​X[0] 
xor_odd​​=​​X[1] 
add_odd​​=​​X[1] 
for​​i​​in​​range(2,​​len(X)): 
​​​​​​​​if​​i​​%​​2​​==​​0: 
  ​​xor_even​​^=​​X[i] 
  ​​add_even​​+=​​X[i] 
​​​​​​​​else: 
  ​​xor_odd​​^=​​X[i] 
  ​​add_odd​​+=​​X[i] 
 
v3​​=​​23 
for​​i​​in​​range(len(X)): 
​​​​​​​​v3​​=​​(X[i]​​<<​​i)​​+​​7​​*​​v3 
v3​​=​​v3​​>>​​4 
 
s.add(add_even​​%​​10​​==​​8) 
s.add(add_odd​​%​​10​​==​​add_even​​%​​10) 
s.add(xor_even​​^​​xor_odd​​==​​90) 
s.add(xor_half​​==​​21) 
s.add(xor_odd​​==​​56) 
s.add((add_odd​​+​​add_even)​​/​​10​​==​​116) 
6
s.add((add_odd​​+​​2*add_even)​​/​​10​​==​​183) 
s.add(X[1]​​==​​ord('3')) 
s.add(X[5]​​==​​ord('5')) 
s.add(X[8]​​==​​ord('4')) 
s.add(X[10]​​==​​ord('7')) 
s.add(v3​​==​​0xFD4E6A44) 
 
if​​s.check()​​==​​sat: 
​​​​​​​​m​​=​​s.model() 
​​​​​​​​x​​=​​[(chr(m.evaluate(X[i]).as_long()))​​for​​i​​in​​range(length)] 
​​​​​​​​print("flag{yOu_%s_3v3r}"​​%​​''.join(x)) 
else: 
​​​​​​​​print("nope") 
Flag:​ ​​flag{yOu_r3ver5eM4s7er_3v3r}
Whoami​ ​(400​ ​pts)
Diberikan sebuah ​binary Windows. Lakukan ​decompile dengan IDA Pro dan didapatkan
pseudocode​​ ​sebagai​ ​berikut.
void​​__noreturn​​start()​​{   
​​​​v0​​=​​GetModuleFileNameA(0,​​Filename,​​0x104u); 
​​​​v1​​=​​v0; 
​​​​do​​{ 
if​​(​​Filename[v1]​​==​​92​​) 
  break; 
--v1; 
​​​​} 
​​​​while​​(​​v1​​); 
​​​​v2​​=​​v1​​+​​1; 
​​​​v3​​=​​&Filename[v2]; 
​​​​v4​​=​​4​​*​​(unsigned​​__int64)((v0​​-​​v2)​​%​​11i64); 
​​​​Filename[v0​​-​​v4]​​=​​0; 
​​​​v5​​=​​v0​​-​​v2​​-​​v4; 
​​​​sub_403274(); 
​​​​sub_4032D0(v3,​​v5); 
​​​​v6​​=​​(char​​*)sub_403344(); 
​​​​sub_4010B9(); 
​​​​v7​​=​​&unk_405000; 
​​​​v8​​=​​32; 
​​​​do​​{ 
v9​​=​​*v6++; 
*v7++​​^=​​v9; 
--v8; 
​​​​} 
​​​​while​​(​​v8​​);   
​​​​sub_4016E8(); 
​​​​sub_401728(&unk_405000,​​32); 
7
​​​​v10​​=​​sub_401788(); 
​​​​v11​​=​​16; 
​​​​v12​​=​​0; 
​​​​v13​​=​​(_BYTE​​*)v10; 
​​​​v14​​=​​0; 
​​​​v15​​=​​&unk_405021; 
​​​​do​​{ 
LOBYTE(v14)​​=​​*v13++; 
LOBYTE(v14)​​=​​*v15++​​^​​v14; 
v12​​+=​​v14; 
--v11; 
​​​​} 
​​​​while​​(​​v11​​); 
​​​​if​​(​​v12​​)​​{ 
v16​​=​​Caption; 
v17​​=​​Caption; 
​​​​} 
​​​​else​​{ 
v16​​=​​(const​​CHAR​​*)&unk_405000; 
v17​​=​​aNiceGanIniFlag; 
​​​​} 
​​​​MessageBoxA(0,​​v16,​​v17,​​0); 
​​​​ExitProcess(0); 
} 
Karena ​binary tersebut telah di-​strip​, beberapa fungsi terlihat tidak jelas apa kegunaannya.
Contohnya​ ​adalah​ ​fungsi​ ​ini.
_DWORD​​*sub_4016E8()​​{ 
​​​​dword_405500​​=​​0; 
​​​​dword_405504​​=​​0; 
​​​​memset(&byte_4054B0,​​0,​​0x40u); 
​​​​result​​=​​dword_4054F0; 
​​​​dword_4054F0[0]​​=​​0x67452301; 
​​​​dword_4054F0[1]​​=​​0xEFCDAB89; 
​​​​dword_4054F0[2]​​=​​0x98BADCFE; 
​​​​dword_4054F0[3]​​=​​0x10325476; 
​​​​return​​result; 
} 
Akan tetapi, setelah melakukan ​googling salah satu konstanta (misalnya ​0xEFCDAB89​)​, saya
menemukan sebuah ​source code C dengan fungsi tersebut menginisialisasi ​state dari MD5.
Dengan cara yang sama, selain MD5 diketahui juga bahwa terdapat fungsi untuk menghitung
nilai hash SHA-256. Dengan info tadi, ​pseudocode​-nya kini dapat diubah sehingga lebih mudah
dibaca.
void​​__noreturn​​start()​​{ 
​​​​v0​​=​​GetModuleFileNameA(0,​​Filename,​​0x104u); 
8
​​​​v1​​=​​v0; 
​​​​do​​{ 
if​​(​​Filename[v1]​​==​​''​​) 
  break; 
--v1; 
​​​​} 
​​​​while​​(​​v1​​); 
​​​​v2​​=​​v1​​+​​1; 
​​​​v3​​=​​&Filename[v2]; 
​​​​v4​​=​​4​​*​​((v0​​-​​v2)​​%​​11i64); 
​​​​Filename[v0​​-​​v4]​​=​​0; 
​​​​v5​​=​​v0​​-​​v2​​-​​v4; 
​​​​sha256_init(); 
​​​​sha256_update(v3,​​v5); 
​​​​v8​​=​​sha256_finish(v6,​​v7); 
​​​​sub_4010B9(v8); 
​​​​v9​​=​​&unk_405000; 
​​​​v10​​=​​32; 
​​​​do​​{ 
v11​​=​​*v8; 
v8​​=​​(v8​​+​​1); 
*v9++​​^=​​v11; 
--v10; 
​​​​} 
​​​​while​​(​​v10​​); 
​​​​md5_init(); 
​​​​md5_update(&unk_405000,​​32u); 
​​​​v12​​=​​md5_final(); 
​​​​v13​​=​​16; 
​​​​v14​​=​​0; 
​​​​v15​​=​​v12; 
​​​​v16​​=​​0; 
​​​​v17​​=​​&unk_405021; 
​​​​do​​{ 
LOBYTE(v16)​​=​​*v15++; 
LOBYTE(v16)​​=​​*v17++​​^​​v16; 
v14​​+=​​v16; 
--v13; 
​​​​} 
​​​​while​​(​​v13​​); 
​​​​if​​(​​v14​​)​​{ 
v18​​=​​Caption; 
v19​​=​​Caption; 
​​​​}​​else​​{ 
v18​​=​​&unk_405000; 
v19​​=​​aNiceGanIniFlag; 
​​​​} 
​​​​MessageBoxA(0,​​v18,​​v19,​​0); 
​​​​ExitProcess(0); 
} 
Fungsi​ ​​sub_4010B9​​ ​adalah​ ​fungsi​ ​sebagai​ ​berikut.
9
 
void​​__usercall​​sub_4010B9(int​​a1@<esi>)​​{ 
​​​​for​​(i​​=​​0;​​i​​<​​25​​&&​​(*(byte_405037[i]​​+​​a1)​​^​​*(byte_405031[i​​%​​6]​​+ 
a1))​​==​​byte_405051[i];​​++i)​​{   
​​​​}   
} 
Fungsi tersebut hanyalah ​looping ​yang dalamnya kosong. Akan tetapi, saya menduga fungsi
tersebut melakukan pengecekan apakah input kita sudah benar apa belum, yaitu benar jika
berhasil​ ​melakukan​ ​​looping​​ ​dari​ ​awal​ ​sampai​ ​akhir.
Pseudocode-nya​ ​dapat​ ​disederhanakan​ ​lagi​ ​seperti​ ​ini.
filename​​=​​GetFileName() 
filename​​=​​filename[:-(4​​*​​(len(filename)​​%​​11))] 
 
v_sha256​​=​​sha256(filename) 
check(v_sha256) 
xor​​=​​v_sha256​​^​​unk_405000 
if​​md5(xor)​​==​​unk_405021: 
​​​​flag​​=​​xor 
else: 
​​​​nope 
Nama file haruslah mempunyai panjang yang jika di-modulus ​11 bernilai ​1​, karena saya
mengasumsikan hal tersebut untuk menghilangkan string “.exe” (panjangnya ​4​, sehingga ​-4 *   
1 = -4​) pada variabel ​filename​. Dengan asumsi tersebut, panjang minimum ​filename   
adalah ​12​, dengan ​4 karakter terakhir adalah “.exe”. Dengan asumsi ​possible characters adalah
[A-Za-z0-9_]{8}​, maka jika dilakukan ​bruteforce dibutuhkan percobaan sebanyak ​63 ** 8     
=​​248155780267521​​ ​kali,​ ​sehingga​ ​tidak​ ​​feasible​​ ​dilakukan.
Cara lainnya adalah dengan menggunakan ​constraint dari fungsi ​sub_4010B9​. Fungsi tersebut
disederhanakan​ ​menjadi​ ​seperti​ ​ini.
def​​check(v_sha256): 
​​​​​​​​for​​i​​in​​range(25): 
  ​​if​​v_sha256[idx1[i]]​​^​​v_sha256[idx2[i​​%​​6]]​​!=​​check_sha256[i]: 
  ​​return​​False 
​​​​​​​​return​​True 
Masalah lainnya adalah setiap ​byte pada ​v_sha256 dapat bernilai dari ​0x00 hingga ​0xFF​,
sehingga ​bruteforce juga tidak ​feasible​. Akan tetapi, jika diperhatikan, nilai variabel ​xor adalah
flagnya! Sehingga pasti karakter pada xor hanyalah ​[A-Za-z0-9_{}]​, dimulai dengan
string ​flag{​, dan diakhiri karakter ​}. Dengan begitu, ​key space untuk melakukan ​bruteforce
10
jauh berkurang. Permasalahan ​constraint seperti ini dapat dicari solusinya dengan Z3. Terakhir,
lakukan pengecekan dengan MD5. Jika salah, cari solusi lain. Jika benar, maka solusi tersebut
sudah​ ​tepat.​ ​Solver​ ​untuk​ ​soal​ ​ini​ ​adalah​ ​sebagai​ ​berikut.
#!/usr/bin/env​​python3 
from​​z3​​import​​* 
from​​hashlib​​import​​md5 
 
def​​main(): 
​​​​​​​​xor_sha​​=​​[0x67,​​0x72,​​0x9F,​​0x0C7,​​0x0B1,​​0x96,​​0x72,​​0x4B,​​0x19,​​0x82, 
0x35,​​0x0C,​​0x0E7,​​0x0D6,​​0x0AD,​​0x0A9,​​0x9F,​​0x3D,​​0x0A6,​​0x68,​​0x89, 
0x0F6,​​0x25,​​0x0A6,​​0x0A0,​​0x96,​​0x8F,​​0x64,​​0x0D4,​​0x56,​​0x0F4,​​0x0BE] 
​​​​​​​​md5_flag​​=​​[0x9F,​​0x0A,​​0x24,​​0x0BA,​​0x92,​​0x85,​​0x0EB,​​0x5E,​​0x0FC, 
0x0DB,​​0x57,​​0x0C2,​​0x3A,​​0x5,​​0x63,​​0x0F7] 
​​​​​​​​md5_flag​​=​​bytes(md5_flag) 
 
​​​​​​​​check​​=​​[0x0C9,​​0x0E0,​​0x0D8,​​0x9F,​​0x25,​​0x0FD,​​0x0AB,​​0x99,​​0x0C8, 
0x1E,​​0x3A,​​0x0B5,​​0x5C,​​0x4C,​​0x0BB,​​0x0B,​​0x1E,​​0x2D,​​0x1C,​​0x3C,​​0x22, 
0x3E,​​0x0B0,​​0x0DC,​​0x0D8] 
​​​​​​​​idx1​​=​​[0x13,​​0x8,​​0x0E,​​0x0B,​​0x18,​​0x0D,​​0x1B,​​0x11,​​0x5,​​0x14,​​0x17, 
0x1E,​​0x19,​​0x0C,​​0x1C,​​0x10,​​0x9,​​0x1D,​​0x1A,​​0x0F,​​0x7,​​0x15,​​0x0A,​​0x12, 
0x6,​​0x16] 
​​​​​​​​idx2​​=​​[0x2,​​0x4,​​0x0,​​0x3,​​0x1F,​​0x1] 
 
​​​​​​​​s​​=​​Solver() 
​​​​​​​​X​​=​​[​​BitVec('x%s'​​%​​i,​​8)​​for​​i​​in​​range(32)​​] 
 
​​​​​​​​#​​checker's​​constraints 
​​​​​​​​for​​i,​​c​​in​​enumerate(check): 
  ​​i1​​=​​idx1[i] 
  ​​i2​​=​​idx2[i​​%​​6] 
  ​​s.add((X[i1]​​^​​X[i2])​​==​​c) 
 
​​​​​​​​#​​charset​​constraints 
​​​​​​​​for​​i,​​x​​in​​enumerate(X): 
  ​​x_xor​​=​​x​​^​​xor_sha[i] 
  ​​s.add(Or( 
  ​​And(x_xor​​>=​​ord('A'),​​x_xor​​<=​​ord('Z')), 
  ​​And(x_xor​​>=​​ord('a'),​​x_xor​​<=​​ord('z')), 
  ​​And(x_xor​​>=​​ord('0'),​​x_xor​​<=​​ord('9')), 
  ​​x_xor​​==​​ord('_'), 
  ​​x_xor​​==​​ord('{'), 
  ​​x_xor​​==​​ord('}'), 
  ​​)) 
 
​​​​​​​​#​​suffix​​and​​prefix​​constraints 
​​​​​​​​s.add(X[0]​​^​​xor_sha[0]​​==​​ord('f')) 
​​​​​​​​s.add(X[1]​​^​​xor_sha[1]​​==​​ord('l')) 
​​​​​​​​s.add(X[2]​​^​​xor_sha[2]​​==​​ord('a')) 
​​​​​​​​s.add(X[3]​​^​​xor_sha[3]​​==​​ord('g')) 
​​​​​​​​s.add(X[4]​​^​​xor_sha[4]​​==​​ord('{')) 
​​​​​​​​s.add(X[-1]​​^​​xor_sha[-1]​​==​​ord('}')) 
11
 
​​​​​​​​#​​explore​​all​​solutions 
​​​​​​​​while​​s.check()​​==​​sat: 
  ​​m​​=​​s.model() 
  ​​sha256​​=​​[m.evaluate(x).as_long()​​for​​x​​in​​X] 
  ​​flag​​=​​[x​​^​​xor_sha[i]​​for​​i,​​x​​in​​enumerate(sha256)] 
 
  ​​#​​check​​md5 
  ​​h​​=​​md5(bytes(flag)) 
  ​​if​​h.digest()​​==​​md5_flag: 
  ​​sha256​​=​​''.join([hex(c)[2:].zfill(2)​​for​​c​​in​​sha256]) 
  ​​flag​​=​​''.join([chr(c)​​for​​c​​in​​flag]) 
 
  ​​print("SHA256:",​​sha256) 
  ​​print("Flag:",​​flag) 
  ​​break 
 
  ​​#​​prevent​​same​​model​​for​​next​​solution 
  ​​s.add(Or([x​​!=​​m[x]​​for​​x​​in​​X])) 
 
if​​__name__​​==​​'__main__': 
​​​​​​​​main() 
Didapat SHA-256 untuk ​filename adalah
011efea0cac926232add733f86e3d9f6ab53c237be9e40f9e6a2e255ba33abc3 yang
jika di-​googling merupakan hash dari kata ​P4ssw0rd​. Sehingga jika nama file diganti dari
siapaaku.exe​​ ​menjadi​ ​​P4ssw0rd.exe​,​ ​flag​ ​akan​ ​ditampilkan.
Flag:​ ​​flag{_Th3_F3a5t_4nd_7he_F4m1ne_} 
12

More Related Content

PDF
Laporan ai modul 3-if b 2014-14102055-deprilana ego prakasa
PDF
Boost.勉強会#4 Boost.Proto
ODP
C++14 reflections
PDF
An introduction to functional programming with Go [redux]
PDF
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
PDF
Bài tập tuần 2
ODP
Антон Полухин. C++17
PPTX
Programming Java - Lection 03 - Classes - Lavrentyev Fedor
Laporan ai modul 3-if b 2014-14102055-deprilana ego prakasa
Boost.勉強会#4 Boost.Proto
C++14 reflections
An introduction to functional programming with Go [redux]
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Bài tập tuần 2
Антон Полухин. C++17
Programming Java - Lection 03 - Classes - Lavrentyev Fedor

What's hot (20)

DOCX
exercise of basic computer programming.docx
PDF
Java Thread Cronometro
PDF
[C++ Korea] Effective Modern C++ Study, Item 27, 29 - 30
PDF
Java AWT Calculadora
DOCX
Danna y felix 10°
PPTX
Алексей Кутумов, C++ без исключений, часть 3
PDF
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
PPTX
Clang-tidy: путешествие внутрь AST C++
PDF
Cours de C++, en français, 2002 - Cours 1.3
DOCX
EJEMPLOS DESARROLLADOS
PDF
Sobrecarga e Sobrescrita - Preparatório Certificação - OCAJP7 - Aula 2 - F
PPTX
20150415 csharp6.0
PPT
Шаблоны проектирования 2
PPT
DOCX
Taller de string(java)
PDF
ECMAscript 2015 aka ES6 : à la découverte du nouveau javascript
DOC
Java
PPTX
es6.concurrency()
exercise of basic computer programming.docx
Java Thread Cronometro
[C++ Korea] Effective Modern C++ Study, Item 27, 29 - 30
Java AWT Calculadora
Danna y felix 10°
Алексей Кутумов, C++ без исключений, часть 3
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Clang-tidy: путешествие внутрь AST C++
Cours de C++, en français, 2002 - Cours 1.3
EJEMPLOS DESARROLLADOS
Sobrecarga e Sobrescrita - Preparatório Certificação - OCAJP7 - Aula 2 - F
20150415 csharp6.0
Шаблоны проектирования 2
Taller de string(java)
ECMAscript 2015 aka ES6 : à la découverte du nouveau javascript
Java
es6.concurrency()
Ad

More from idsecconf (20)

PDF
IDSECCONF2024 Capture The FLag Write up - 3 MAS MAS
PDF
IDSECCONF2024 - Rifqi Hilmy Zhafrant - Hunting and Exploiting GraphQL Vulnera...
PDF
IDSECCONF2024 - Arief Karfianto - AI-Enhanced Security Analysis in Requiremen...
PDF
IDSECCONF2024 - Ryan Fabella, Daniel Dhaniswara - Keamanan Siber Pada Kendara...
PDF
IDSECCONF2024 - Angela Oryza - ITS Nabu-Platform Pelatihan Keamanan Siber den...
PDF
IDSECCONF2024 - Rama Tri Nanda - MQTT hacking, RCE in Smart Router.pdf
PDF
IDSECCONF2024 - Muhammad Dwison - The Implementation Of One Pixel Attack To S...
PDF
IDSECCONF2024 - Kang Ali - Local LLM can Simulate Apt Malware With Jailbreak ...
PDF
IDSECCONF2024 - Brian Nasywa - Comparison of Quantum Key Distribution Protoco...
PDF
idsecconf2023 - Mochammad Riyan Firmansyah - Takeover Cloud Managed Router vi...
PDF
idsecconf2023 - Neil Armstrong - Leveraging IaC for Stealthy Infrastructure A...
PDF
idsecconf2023 - Mangatas Tondang, Wahyu Nuryanto - Penerapan Model Detection ...
PDF
idsecconf2023 - Rama Tri Nanda - Hacking Smart Doorbell.pdf
PDF
idsecconf2023 - Akshantula Neha, Mohammad Febri Ramadlan - Cyber Harmony Auto...
PDF
idsecconf2023 - Aan Wahyu - Hide n seek with android app protections and beat...
PDF
idsecconf2023 - Satria Ady Pradana - Launch into the Stratus-phere Adversary ...
PDF
Ali - The Journey-Hack Electron App Desktop (MacOS).pdf
PDF
Muh. Fani Akbar - Infiltrate Into Your AWS Cloud Environment Through Public E...
PDF
Rama Tri Nanda - NFC Hacking Hacking NFC Reverse Power Supply Padlock.pdf
PDF
Arief Karfianto - Proposed Security Model for Protecting Patients Data in Ele...
IDSECCONF2024 Capture The FLag Write up - 3 MAS MAS
IDSECCONF2024 - Rifqi Hilmy Zhafrant - Hunting and Exploiting GraphQL Vulnera...
IDSECCONF2024 - Arief Karfianto - AI-Enhanced Security Analysis in Requiremen...
IDSECCONF2024 - Ryan Fabella, Daniel Dhaniswara - Keamanan Siber Pada Kendara...
IDSECCONF2024 - Angela Oryza - ITS Nabu-Platform Pelatihan Keamanan Siber den...
IDSECCONF2024 - Rama Tri Nanda - MQTT hacking, RCE in Smart Router.pdf
IDSECCONF2024 - Muhammad Dwison - The Implementation Of One Pixel Attack To S...
IDSECCONF2024 - Kang Ali - Local LLM can Simulate Apt Malware With Jailbreak ...
IDSECCONF2024 - Brian Nasywa - Comparison of Quantum Key Distribution Protoco...
idsecconf2023 - Mochammad Riyan Firmansyah - Takeover Cloud Managed Router vi...
idsecconf2023 - Neil Armstrong - Leveraging IaC for Stealthy Infrastructure A...
idsecconf2023 - Mangatas Tondang, Wahyu Nuryanto - Penerapan Model Detection ...
idsecconf2023 - Rama Tri Nanda - Hacking Smart Doorbell.pdf
idsecconf2023 - Akshantula Neha, Mohammad Febri Ramadlan - Cyber Harmony Auto...
idsecconf2023 - Aan Wahyu - Hide n seek with android app protections and beat...
idsecconf2023 - Satria Ady Pradana - Launch into the Stratus-phere Adversary ...
Ali - The Journey-Hack Electron App Desktop (MacOS).pdf
Muh. Fani Akbar - Infiltrate Into Your AWS Cloud Environment Through Public E...
Rama Tri Nanda - NFC Hacking Hacking NFC Reverse Power Supply Padlock.pdf
Arief Karfianto - Proposed Security Model for Protecting Patients Data in Ele...
Ad

Writeup ctf online idsecconf 2017

  • 1. Writeup​ ​CTF​ ​Online​ ​IDSECCONF​ ​2017 Visat Misc 1 Dungeon​ ​(100​ ​pts) 1 Reverse 3 Logang​ ​(20​ ​pts) 3 Darwin​ ​(100​ ​pts) 3 Whoami​ ​(400​ ​pts) 7
  • 2. Misc Dungeon​ ​(100​ ​pts) Diberikan​ ​sebuah​ ​​web​ ​service​​ ​yang​ ​mempunyai​ ​labirin​ ​seperti​ ​pada​ ​gambar. 1
  • 3. Misi kita adalah memberikan arah jalan dari P menuju E. Hal ini dapat dilakukan dengan algoritma​ ​BFS.​ ​Buat​ ​​script​​ ​untuk​ ​melakukannya​ ​secara​ ​otomatis. #!/usr/bin/env​​python    from​​pwn​​import​​*    dr​​=​​[0,1,0,-1]  dc​​=​​[1,0,-1,0]  dd​​=​​['R',​​'D',​​'L',​​'U']    def​​bfs(maze,​​rowc,​​colc):  ​​​​​​​​queue​​=​​[(rowc,​​colc,​​[])]  ​​​​​​​​visited​​=​​set()  ​​​​​​​​while​​queue:    ​​r,c,l​​=​​queue.pop(0)    ​​visited.add((r,c))    ​​for​​k​​in​​range(4):    ​​row​​=​​r+dr[k]    ​​col​​=​​c+dc[k]    ​​if​​row​​<​​0​​or​​row​​>=​​len(maze):    ​​continue    ​​if​​col​​<​​0​​or​​col​​>=​​len(maze[0]):    ​​continue    ​​if​​maze[row][col]​​==​​'E':    ​​return​​l​​+​​[dd[k]]    ​​if​​maze[row][col]​​!=​​'​​':    ​​continue    ​​if​​(row,col)​​in​​visited:    ​​continue    ​​queue.append((row,col,l+[dd[k]]))    r​​=​​remote('62.4.3.98',​​10111)  print​​r.recvuntil("start")  r.recvline()  r.sendline("")    while​​1:  ​​​​​​​​s​​=​​r.recvline()  ​​​​​​​​print​​s  ​​​​​​​​if​​"flag"​​in​​s:    ​​print​​s    ​​break  ​​​​​​​​s​​=​​r.recvline()  ​​​​​​​​s​​=​​s.split()  ​​​​​​​​row​​=​​int(s[-1].strip())    ​​​​​​​​s​​=​​r.recvline()  ​​​​​​​​s​​=​​s.split()  ​​​​​​​​col​​=​​int(s[-1].strip())    ​​​​​​​​print​​row,col  2
  • 4.   ​​​​​​​​maze​​=​​[]  ​​​​​​​​for​​i​​in​​range(row):    ​​s​​=​​r.recvline().strip()    ​​maze.append(s)      ​​if​​'P'​​in​​s:    ​​rowc​​=​​i    ​​colc​​=​​s.index('P')    ​​​​​​​​for​​c​​in​​bfs(maze,rowc,colc):    ​​print​​r.recvline(),    ​​r.recvline()    ​​r.sendline(c)    ​​​​​​​​s​​=​​r.recvline()  ​​​​​​​​if​​"flag"​​in​​s:    ​​print​​s    ​​break  ​​​​​​​​r.sendline("")  Setelah​ ​maze​ ​ke-10,​ ​didapatkan​ ​flag. Flag:​ ​​flag{pOwer_pOLe_paPAh}  Reverse Logang​ ​(20​ ​pts) Diberikan sebuah ​binary ELF 32-bit yang menggunakan bahasa Go. Langkah pertama dalam reversing​​ ​biasanya​ ​adalah​ ​mencari​ ​flag​ ​dengan​ ​menggunakan​ ​command​ ​​strings​​ ​dan​ ​​grep​. $​​strings​​logang​​|​​grep​​-iE​​"^[a-zA-Z0-9_{}]*$"​​|​​less  Terdapat string menarik, yaitu ​flag{​, ​go_rEverse​, dan ​_aLa_pApah}​. Jika digabungkan akan​ ​didapatkan​ ​flag. Flag:​ ​​flag{go_rEverse_aLa_pApah} Darwin​ ​(100​ ​pts) Diberikan sebuah ​binary Mach-O 32 bit. Setelah melakukan ​decompile dengan IDA Pro, pseudocode​-nya​ ​adalah​ ​sebagai​ ​berikut. 3
  • 5. signed​​int​​start()​​{  ​​​​​​​​memset(v3,​​0,​​0x20u);  ​​​​​​​​printf("Enter​​the​​key​​:​​");  ​​​​​​​​v2​​=​​0;  ​​​​​​​​fgets(v3,​​32,​​__stdinp);  ​​​​​​​​while​​(​​v2​​<​​32​​)​​{    ​​v0​​=​​0;    ​​if​​(​​v3[v2]​​==​​10​​)    ​​v0​​=​​-10;    ​​v3[v2++]​​+=​​v0;  ​​​​​​​​}  ​​​​​​​​if​​(​​sub_1A30(v3)​​)    ​​printf("Congratz,​​the​​flag​​:nflag{yOu_%s_3v3r}n",​​v3);  ​​​​​​​​else    ​​printf("Wrong​​%s​​not​​the​​key.n",​​v3);  }  Program meminta masukan ​key​, lalu dilakukan pengecekan dengan fungsi ​sub_1A30​. Jika fungsi​ ​bernilai​ ​​true​,​ ​maka​ ​flag-nya​ ​adalah​ ​​flag{yOu_<key>_3v3r}​. bool​​sub_1A30(char​​*a1)​​{  ​​​​​​​​v18​​=​​strlen(a1);  ​​​​​​​​v17​​=​​0;  ​​​​​​​​v16​​=​​0;  ​​​​​​​​v15​​=​​0;  ​​​​​​​​v14​​=​​0;  ​​​​​​​​v13​​=​​0;  ​​​​​​​​v12​​=​​0;      ​​​​​​​​for​​(​​i​​=​​0;​​i​​<​​v18;​​++i​​)​​{    ​​if​​(​​i​​%​​2​​)    ​​v7​​=​​*(a1​​+​​i)​​^​​v14;    ​​else    ​​v7​​=​​v14;    ​​v14​​=​​v7;    ​​if​​(​​i​​%​​2​​==​​1​​)    ​​v6​​=​​v13;    ​​else    ​​v6​​=​​*(a1​​+​​i)​​^​​v13;    ​​v13​​=​​v6;    ​​if​​(​​i​​%​​2​​)    ​​v5​​=​​0;    ​​else    ​​v5​​=​​*(a1​​+​​i);    ​​v17​​+=​​v5;    ​​if​​(​​i​​%​​2​​==​​1​​)    ​​v4​​=​​*(a1​​+​​i)​​^​​v15;    ​​else    ​​v4​​=​​v15;    ​​v15​​=​​v4;  ​​​​​​​​}  4
  • 6.     ​​​​​​​​for​​(​​j​​=​​0;​​j​​<​​v18​​/​​2;​​++j​​)    ​​v12​​^=​​*(a1​​+​​j);      ​​​​​​​​for​​(​​k​​=​​0;​​k​​<​​v18;​​++k​​)​​{    ​​if​​(​​k​​%​​2​​)    ​​v3​​=​​*(a1​​+​​k);    ​​else    ​​v3​​=​​0;    ​​v16​​+=​​v3;    ​​if​​(​​k​​%​​2​​)    ​​v2​​=​​v15;    ​​else    ​​v2​​=​​*(a1​​+​​k)​​^​​v15;    ​​v15​​=​​v2;  ​​​​​​​​}    ​​​​​​​​v11​​=​​sub_19C0(a1);  ​​​​​​​​return​​v17​​%​​10​​==​​8    ​​&&​​v16​​%​​10​​==​​v17​​%​​10    ​​&&​​v18​​==​​13    ​​&&​​v15​​==​​90    ​​&&​​v12​​==​​21    ​​&&​​v14​​==​​56    ​​&&​​(v16​​+​​v17)​​/​​10​​==​​116    ​​&&​​(v16​​+​​2​​*​​v17)​​/​​10​​==​​183      ​​&&​​*(a1​​+​​1)​​==​​'3'    ​​&&​​*(a1​​+​​5)​​==​​'5'    ​​&&​​*(a1​​+​​8)​​==​​'4'    ​​&&​​*(a1​​+​​10)​​==​​'7'    ​​&&​​v11​​==​​0xFD4E6A44;  }    int​​sub_19C0(const​​char​​*a1)​​{  ​​​​​​​​v4​​=​​strlen(a1);  ​​​​​​​​v3​​=​​23;  ​​​​​​​​for​​(​​i​​=​​0;​​i​​<​​v4;​​++i​​)    ​​v3​​=​​(a1[i]​​<<​​i)​​+​​7​​*​​v3;  ​​​​​​​​return​​v3​​>>​​4;  }  Terdapat beberapa kondisi yang harus dipenuhi beberapa variabel agar fungsi tersebut bernilai true​.​ ​Evaluasi​ ​dari​ ​variabel​ ​tersebut​ ​adalah​ ​sebagai​ ​berikut: ● v18​​ ​adalah​ ​panjang​ ​​key​. ● v17​​ ​adalah​ ​penjumlahan​ ​dari​ ​karakter​ ​​key​​ ​berindeks​ ​genap. ● v16​​ ​adalah​ ​penjumlahan​ ​dari​ ​karakter​ ​​key​​ ​berindeks​ ​ganjil. ● v15​​ ​adalah​ ​hasil​ ​xor​ ​semua​ ​karakter​ ​​key​. ● v14​​ ​adalah​ ​hasil​ ​xor​ ​semua​ ​karakter​ ​​key​​ ​berindeks​ ​ganjil. ● v12​​ ​adalah​ ​hasil​ ​xor​ ​karakter​ ​dari​ ​​0​​ ​sampai​ ​​len(key)//2​. ● v11​​ ​adalah​ ​hasil​ ​fungsi​ ​​sub_19c0  5
  • 7. Terdapat beberapa kondisi yang harus dipenuhi variabel tersebut, yang akan kita sebut constraint​. Permasalahan ​constraint seperti ini dapat dicari solusinya dengan cepat dengan menggunakan​ ​Z3.​ ​Solver​ ​script​ ​untuk​ ​​constraint​​ ​ini​ ​adalah​ ​sebagai​ ​berikut. #!/usr/bin/env​​python3    from​​z3​​import​​*  import​​string  import​​itertools    length​​=​​13  X​​=​​[BitVec('x%s'​​%​​i,​​32)​​for​​i​​in​​range(length)]  s​​=​​Solver()    #​​charset​​constraint,​​letters​​+​​digits​​+​​underscore  for​​i​​in​​range(len(X)):  ​​​​​​​​s.add(Or(    ​​And(X[i]​​>=​​ord('A'),​​X[i]​​<=​​ord('Z')),    ​​And(X[i]​​>=​​ord('a'),​​X[i]​​<=​​ord('z')),    ​​And(X[i]​​>=​​ord('0'),​​X[i]​​<=​​ord('9')),    ​​X[i]​​==​​ord('_')  ​​​​​​​​))    xor_half​​=​​X[0]  for​​i​​in​​range(1,​​len(X)​​//​​2):  ​​​​​​​​xor_half​​^=​​X[i]    xor_even​​=​​X[0]  add_even​​=​​X[0]  xor_odd​​=​​X[1]  add_odd​​=​​X[1]  for​​i​​in​​range(2,​​len(X)):  ​​​​​​​​if​​i​​%​​2​​==​​0:    ​​xor_even​​^=​​X[i]    ​​add_even​​+=​​X[i]  ​​​​​​​​else:    ​​xor_odd​​^=​​X[i]    ​​add_odd​​+=​​X[i]    v3​​=​​23  for​​i​​in​​range(len(X)):  ​​​​​​​​v3​​=​​(X[i]​​<<​​i)​​+​​7​​*​​v3  v3​​=​​v3​​>>​​4    s.add(add_even​​%​​10​​==​​8)  s.add(add_odd​​%​​10​​==​​add_even​​%​​10)  s.add(xor_even​​^​​xor_odd​​==​​90)  s.add(xor_half​​==​​21)  s.add(xor_odd​​==​​56)  s.add((add_odd​​+​​add_even)​​/​​10​​==​​116)  6
  • 8. s.add((add_odd​​+​​2*add_even)​​/​​10​​==​​183)  s.add(X[1]​​==​​ord('3'))  s.add(X[5]​​==​​ord('5'))  s.add(X[8]​​==​​ord('4'))  s.add(X[10]​​==​​ord('7'))  s.add(v3​​==​​0xFD4E6A44)    if​​s.check()​​==​​sat:  ​​​​​​​​m​​=​​s.model()  ​​​​​​​​x​​=​​[(chr(m.evaluate(X[i]).as_long()))​​for​​i​​in​​range(length)]  ​​​​​​​​print("flag{yOu_%s_3v3r}"​​%​​''.join(x))  else:  ​​​​​​​​print("nope")  Flag:​ ​​flag{yOu_r3ver5eM4s7er_3v3r} Whoami​ ​(400​ ​pts) Diberikan sebuah ​binary Windows. Lakukan ​decompile dengan IDA Pro dan didapatkan pseudocode​​ ​sebagai​ ​berikut. void​​__noreturn​​start()​​{    ​​​​v0​​=​​GetModuleFileNameA(0,​​Filename,​​0x104u);  ​​​​v1​​=​​v0;  ​​​​do​​{  if​​(​​Filename[v1]​​==​​92​​)    break;  --v1;  ​​​​}  ​​​​while​​(​​v1​​);  ​​​​v2​​=​​v1​​+​​1;  ​​​​v3​​=​​&Filename[v2];  ​​​​v4​​=​​4​​*​​(unsigned​​__int64)((v0​​-​​v2)​​%​​11i64);  ​​​​Filename[v0​​-​​v4]​​=​​0;  ​​​​v5​​=​​v0​​-​​v2​​-​​v4;  ​​​​sub_403274();  ​​​​sub_4032D0(v3,​​v5);  ​​​​v6​​=​​(char​​*)sub_403344();  ​​​​sub_4010B9();  ​​​​v7​​=​​&unk_405000;  ​​​​v8​​=​​32;  ​​​​do​​{  v9​​=​​*v6++;  *v7++​​^=​​v9;  --v8;  ​​​​}  ​​​​while​​(​​v8​​);    ​​​​sub_4016E8();  ​​​​sub_401728(&unk_405000,​​32);  7
  • 9. ​​​​v10​​=​​sub_401788();  ​​​​v11​​=​​16;  ​​​​v12​​=​​0;  ​​​​v13​​=​​(_BYTE​​*)v10;  ​​​​v14​​=​​0;  ​​​​v15​​=​​&unk_405021;  ​​​​do​​{  LOBYTE(v14)​​=​​*v13++;  LOBYTE(v14)​​=​​*v15++​​^​​v14;  v12​​+=​​v14;  --v11;  ​​​​}  ​​​​while​​(​​v11​​);  ​​​​if​​(​​v12​​)​​{  v16​​=​​Caption;  v17​​=​​Caption;  ​​​​}  ​​​​else​​{  v16​​=​​(const​​CHAR​​*)&unk_405000;  v17​​=​​aNiceGanIniFlag;  ​​​​}  ​​​​MessageBoxA(0,​​v16,​​v17,​​0);  ​​​​ExitProcess(0);  }  Karena ​binary tersebut telah di-​strip​, beberapa fungsi terlihat tidak jelas apa kegunaannya. Contohnya​ ​adalah​ ​fungsi​ ​ini. _DWORD​​*sub_4016E8()​​{  ​​​​dword_405500​​=​​0;  ​​​​dword_405504​​=​​0;  ​​​​memset(&byte_4054B0,​​0,​​0x40u);  ​​​​result​​=​​dword_4054F0;  ​​​​dword_4054F0[0]​​=​​0x67452301;  ​​​​dword_4054F0[1]​​=​​0xEFCDAB89;  ​​​​dword_4054F0[2]​​=​​0x98BADCFE;  ​​​​dword_4054F0[3]​​=​​0x10325476;  ​​​​return​​result;  }  Akan tetapi, setelah melakukan ​googling salah satu konstanta (misalnya ​0xEFCDAB89​)​, saya menemukan sebuah ​source code C dengan fungsi tersebut menginisialisasi ​state dari MD5. Dengan cara yang sama, selain MD5 diketahui juga bahwa terdapat fungsi untuk menghitung nilai hash SHA-256. Dengan info tadi, ​pseudocode​-nya kini dapat diubah sehingga lebih mudah dibaca. void​​__noreturn​​start()​​{  ​​​​v0​​=​​GetModuleFileNameA(0,​​Filename,​​0x104u);  8
  • 10. ​​​​v1​​=​​v0;  ​​​​do​​{  if​​(​​Filename[v1]​​==​​''​​)    break;  --v1;  ​​​​}  ​​​​while​​(​​v1​​);  ​​​​v2​​=​​v1​​+​​1;  ​​​​v3​​=​​&Filename[v2];  ​​​​v4​​=​​4​​*​​((v0​​-​​v2)​​%​​11i64);  ​​​​Filename[v0​​-​​v4]​​=​​0;  ​​​​v5​​=​​v0​​-​​v2​​-​​v4;  ​​​​sha256_init();  ​​​​sha256_update(v3,​​v5);  ​​​​v8​​=​​sha256_finish(v6,​​v7);  ​​​​sub_4010B9(v8);  ​​​​v9​​=​​&unk_405000;  ​​​​v10​​=​​32;  ​​​​do​​{  v11​​=​​*v8;  v8​​=​​(v8​​+​​1);  *v9++​​^=​​v11;  --v10;  ​​​​}  ​​​​while​​(​​v10​​);  ​​​​md5_init();  ​​​​md5_update(&unk_405000,​​32u);  ​​​​v12​​=​​md5_final();  ​​​​v13​​=​​16;  ​​​​v14​​=​​0;  ​​​​v15​​=​​v12;  ​​​​v16​​=​​0;  ​​​​v17​​=​​&unk_405021;  ​​​​do​​{  LOBYTE(v16)​​=​​*v15++;  LOBYTE(v16)​​=​​*v17++​​^​​v16;  v14​​+=​​v16;  --v13;  ​​​​}  ​​​​while​​(​​v13​​);  ​​​​if​​(​​v14​​)​​{  v18​​=​​Caption;  v19​​=​​Caption;  ​​​​}​​else​​{  v18​​=​​&unk_405000;  v19​​=​​aNiceGanIniFlag;  ​​​​}  ​​​​MessageBoxA(0,​​v18,​​v19,​​0);  ​​​​ExitProcess(0);  }  Fungsi​ ​​sub_4010B9​​ ​adalah​ ​fungsi​ ​sebagai​ ​berikut. 9
  • 11.   void​​__usercall​​sub_4010B9(int​​a1@<esi>)​​{  ​​​​for​​(i​​=​​0;​​i​​<​​25​​&&​​(*(byte_405037[i]​​+​​a1)​​^​​*(byte_405031[i​​%​​6]​​+  a1))​​==​​byte_405051[i];​​++i)​​{    ​​​​}    }  Fungsi tersebut hanyalah ​looping ​yang dalamnya kosong. Akan tetapi, saya menduga fungsi tersebut melakukan pengecekan apakah input kita sudah benar apa belum, yaitu benar jika berhasil​ ​melakukan​ ​​looping​​ ​dari​ ​awal​ ​sampai​ ​akhir. Pseudocode-nya​ ​dapat​ ​disederhanakan​ ​lagi​ ​seperti​ ​ini. filename​​=​​GetFileName()  filename​​=​​filename[:-(4​​*​​(len(filename)​​%​​11))]    v_sha256​​=​​sha256(filename)  check(v_sha256)  xor​​=​​v_sha256​​^​​unk_405000  if​​md5(xor)​​==​​unk_405021:  ​​​​flag​​=​​xor  else:  ​​​​nope  Nama file haruslah mempunyai panjang yang jika di-modulus ​11 bernilai ​1​, karena saya mengasumsikan hal tersebut untuk menghilangkan string “.exe” (panjangnya ​4​, sehingga ​-4 *    1 = -4​) pada variabel ​filename​. Dengan asumsi tersebut, panjang minimum ​filename    adalah ​12​, dengan ​4 karakter terakhir adalah “.exe”. Dengan asumsi ​possible characters adalah [A-Za-z0-9_]{8}​, maka jika dilakukan ​bruteforce dibutuhkan percobaan sebanyak ​63 ** 8      =​​248155780267521​​ ​kali,​ ​sehingga​ ​tidak​ ​​feasible​​ ​dilakukan. Cara lainnya adalah dengan menggunakan ​constraint dari fungsi ​sub_4010B9​. Fungsi tersebut disederhanakan​ ​menjadi​ ​seperti​ ​ini. def​​check(v_sha256):  ​​​​​​​​for​​i​​in​​range(25):    ​​if​​v_sha256[idx1[i]]​​^​​v_sha256[idx2[i​​%​​6]]​​!=​​check_sha256[i]:    ​​return​​False  ​​​​​​​​return​​True  Masalah lainnya adalah setiap ​byte pada ​v_sha256 dapat bernilai dari ​0x00 hingga ​0xFF​, sehingga ​bruteforce juga tidak ​feasible​. Akan tetapi, jika diperhatikan, nilai variabel ​xor adalah flagnya! Sehingga pasti karakter pada xor hanyalah ​[A-Za-z0-9_{}]​, dimulai dengan string ​flag{​, dan diakhiri karakter ​}. Dengan begitu, ​key space untuk melakukan ​bruteforce 10
  • 12. jauh berkurang. Permasalahan ​constraint seperti ini dapat dicari solusinya dengan Z3. Terakhir, lakukan pengecekan dengan MD5. Jika salah, cari solusi lain. Jika benar, maka solusi tersebut sudah​ ​tepat.​ ​Solver​ ​untuk​ ​soal​ ​ini​ ​adalah​ ​sebagai​ ​berikut. #!/usr/bin/env​​python3  from​​z3​​import​​*  from​​hashlib​​import​​md5    def​​main():  ​​​​​​​​xor_sha​​=​​[0x67,​​0x72,​​0x9F,​​0x0C7,​​0x0B1,​​0x96,​​0x72,​​0x4B,​​0x19,​​0x82,  0x35,​​0x0C,​​0x0E7,​​0x0D6,​​0x0AD,​​0x0A9,​​0x9F,​​0x3D,​​0x0A6,​​0x68,​​0x89,  0x0F6,​​0x25,​​0x0A6,​​0x0A0,​​0x96,​​0x8F,​​0x64,​​0x0D4,​​0x56,​​0x0F4,​​0x0BE]  ​​​​​​​​md5_flag​​=​​[0x9F,​​0x0A,​​0x24,​​0x0BA,​​0x92,​​0x85,​​0x0EB,​​0x5E,​​0x0FC,  0x0DB,​​0x57,​​0x0C2,​​0x3A,​​0x5,​​0x63,​​0x0F7]  ​​​​​​​​md5_flag​​=​​bytes(md5_flag)    ​​​​​​​​check​​=​​[0x0C9,​​0x0E0,​​0x0D8,​​0x9F,​​0x25,​​0x0FD,​​0x0AB,​​0x99,​​0x0C8,  0x1E,​​0x3A,​​0x0B5,​​0x5C,​​0x4C,​​0x0BB,​​0x0B,​​0x1E,​​0x2D,​​0x1C,​​0x3C,​​0x22,  0x3E,​​0x0B0,​​0x0DC,​​0x0D8]  ​​​​​​​​idx1​​=​​[0x13,​​0x8,​​0x0E,​​0x0B,​​0x18,​​0x0D,​​0x1B,​​0x11,​​0x5,​​0x14,​​0x17,  0x1E,​​0x19,​​0x0C,​​0x1C,​​0x10,​​0x9,​​0x1D,​​0x1A,​​0x0F,​​0x7,​​0x15,​​0x0A,​​0x12,  0x6,​​0x16]  ​​​​​​​​idx2​​=​​[0x2,​​0x4,​​0x0,​​0x3,​​0x1F,​​0x1]    ​​​​​​​​s​​=​​Solver()  ​​​​​​​​X​​=​​[​​BitVec('x%s'​​%​​i,​​8)​​for​​i​​in​​range(32)​​]    ​​​​​​​​#​​checker's​​constraints  ​​​​​​​​for​​i,​​c​​in​​enumerate(check):    ​​i1​​=​​idx1[i]    ​​i2​​=​​idx2[i​​%​​6]    ​​s.add((X[i1]​​^​​X[i2])​​==​​c)    ​​​​​​​​#​​charset​​constraints  ​​​​​​​​for​​i,​​x​​in​​enumerate(X):    ​​x_xor​​=​​x​​^​​xor_sha[i]    ​​s.add(Or(    ​​And(x_xor​​>=​​ord('A'),​​x_xor​​<=​​ord('Z')),    ​​And(x_xor​​>=​​ord('a'),​​x_xor​​<=​​ord('z')),    ​​And(x_xor​​>=​​ord('0'),​​x_xor​​<=​​ord('9')),    ​​x_xor​​==​​ord('_'),    ​​x_xor​​==​​ord('{'),    ​​x_xor​​==​​ord('}'),    ​​))    ​​​​​​​​#​​suffix​​and​​prefix​​constraints  ​​​​​​​​s.add(X[0]​​^​​xor_sha[0]​​==​​ord('f'))  ​​​​​​​​s.add(X[1]​​^​​xor_sha[1]​​==​​ord('l'))  ​​​​​​​​s.add(X[2]​​^​​xor_sha[2]​​==​​ord('a'))  ​​​​​​​​s.add(X[3]​​^​​xor_sha[3]​​==​​ord('g'))  ​​​​​​​​s.add(X[4]​​^​​xor_sha[4]​​==​​ord('{'))  ​​​​​​​​s.add(X[-1]​​^​​xor_sha[-1]​​==​​ord('}'))  11
  • 13.   ​​​​​​​​#​​explore​​all​​solutions  ​​​​​​​​while​​s.check()​​==​​sat:    ​​m​​=​​s.model()    ​​sha256​​=​​[m.evaluate(x).as_long()​​for​​x​​in​​X]    ​​flag​​=​​[x​​^​​xor_sha[i]​​for​​i,​​x​​in​​enumerate(sha256)]      ​​#​​check​​md5    ​​h​​=​​md5(bytes(flag))    ​​if​​h.digest()​​==​​md5_flag:    ​​sha256​​=​​''.join([hex(c)[2:].zfill(2)​​for​​c​​in​​sha256])    ​​flag​​=​​''.join([chr(c)​​for​​c​​in​​flag])      ​​print("SHA256:",​​sha256)    ​​print("Flag:",​​flag)    ​​break      ​​#​​prevent​​same​​model​​for​​next​​solution    ​​s.add(Or([x​​!=​​m[x]​​for​​x​​in​​X]))    if​​__name__​​==​​'__main__':  ​​​​​​​​main()  Didapat SHA-256 untuk ​filename adalah 011efea0cac926232add733f86e3d9f6ab53c237be9e40f9e6a2e255ba33abc3 yang jika di-​googling merupakan hash dari kata ​P4ssw0rd​. Sehingga jika nama file diganti dari siapaaku.exe​​ ​menjadi​ ​​P4ssw0rd.exe​,​ ​flag​ ​akan​ ​ditampilkan. Flag:​ ​​flag{_Th3_F3a5t_4nd_7he_F4m1ne_}  12