완료됨
_IO_str_overflow의 주소

_IO_str_overflow의 주소를 구할 때 강의 내용 보면 아래처럼 _IO_file_jumps 의 주소를 구한 다음에 여기서 0xd8 만큼 더해서 구하는데,

io_file_jumps = libc_base + libc.symbols['_IO_file_jumps']
io_str_overflow = io_file_jumps + 0xd8
fake_vtable = io_str_overflow - 16

심볼 테이블 보면 _IO_str_overflow 함수가 있는 것 같은데 왜 아래처럼 _IO_str_overflow를 바로 구하면 안되는 걸까요?

io_str_overflow = libc_base + libc.symbols['_IO_str_overflow']
fake_vtable = io_str_overflow - 16

그리고 _IO_str_overflow_IO_file_jumps 에서 0xD8 만큼 떨어졌다는 사실은 어디서 찾을 수 있는지도 궁금합니다.

#시스템해킹 #공격기법 #io_file #io_validate_vtable
작성자 정보
더 깊이 있는 답변이 필요할 때
드림핵 팀과 멘토에게 직접 문의해 보세요!
답변 2
qwerty_io
대표 업적 없음

위에서 구한 fake_vtable의 값은 (libc_base + libc.symbols['_IO_file_jumps'] + 0xd8) - 16이며 아래에서 구한 fake_vtable의 값은 (libc_base + libc.symbols['_IO_str_overflow'] - 16)입니다. *(libc_base + libc.symbols['_IO_file_jumps'] + 0xd8)_IO_str_overflow()의 주소를 들고 있습니다. 따라서 libc_base + libc.symbols['_IO_file_jumps'] + 0xd8libc_base + libc.symbols['_IO_str_overflow']은 같지 않습니다.

또한 인자로 주어야 하는 값은 함수의 주소가 아닌 함수를 들고 있는 vtable의 값을 주어야 하기 때문에 위 방법으로 구해야만 합니다. 추가적으로 IO_validate_vtable은 vtable이 _IO_(w)file_*을 저장해 둔 구간 사이에 있는지 검증하기 때문에 다른 임의의 주소를 vtable로 사용할 수 없습니다.

gdb에서 p _IO_file_jumps을 입력하면 위치를 확인하실 수 있으며 x/30gx등으로 실제 떨어진 거리가 얼마인지 확인할 수 있습니다.

2024.11.05. 12:27
avatar
poppo25
휴머노이드

저도 궁금해서 찾아봤는데 아래와 같았습니다

1.0xD8만큼 떨어진 방법을 아는 법

우선 fopen 후에 bp를 걸고 실행해보면 rax에 fp가 저장됩니다. _IO_FILE_plus가 있을텐데, _IO_FILE + vtables입니다
_IO_FILE 의 크기는 0xd0이니까 0xd8을 더하면 vtables의 주소를 구할 수 있습니다

pwndbg> x/x $rax+0xd8
0x108f338:      0x00007a29e060e2a0
pwndbg> x/x 0x00007a29e060e2a0
0x7a29e060e2a0 <_IO_file_jumps>:        0x0000000000000000

_IO_file_jumps 구조체가 있습니다.

pwndbg> p *(struct _IO_jump_t *)0x00007a29e060e2a0
$22 = {
  __dummy = 0, 
  __dummy2 = 0, 
  __finish = 0x7a29e02b22d0 <_IO_new_file_finish>, 
  __overflow = 0x7a29e02b32b0 <_IO_new_file_overflow>, 
  __underflow = 0x7a29e02b2fd0 <_IO_new_file_underflow>, 
  __uflow = 0x7a29e02b4370 <__GI__IO_default_uflow>, 
  __pbackfail = 0x7a29e02b5c00 <__GI__IO_default_pbackfail>, 
  __xsputn = 0x7a29e02b18d0 <_IO_new_file_xsputn>, 
  __xsgetn = 0x7a29e02b1530 <__GI__IO_file_xsgetn>, 
  __seekoff = 0x7a29e02b0b30 <_IO_new_file_seekoff>, 
  __seekpos = 0x7a29e02b4940 <_IO_default_seekpos>, 
  __setbuf = 0x7a29e02b07f0 <_IO_new_file_setbuf>, 
  __sync = 0x7a29e02b0670 <_IO_new_file_sync>, 
  __doallocate = 0x7a29e02a40b0 <__GI__IO_file_doallocate>, 
  __read = 0x7a29e02b18b0 <__GI__IO_file_read>, 
  __write = 0x7a29e02b1130 <_IO_new_file_write>, 
  __seek = 0x7a29e02b08b0 <__GI__IO_file_seek>, 
  __close = 0x7a29e02b07e0 <__GI__IO_file_close>, 
  __stat = 0x7a29e02b1120 <__GI__IO_file_stat>, 
  __showmanyc = 0x7a29e02b5d80 <_IO_default_showmanyc>, 
  __imbue = 0x7a29e02b5d90 <_IO_default_imbue>
}

여기서 x/60gx 이렇게 아래의 값을 출력해보면, 아래쪽에 _IO_str_jumps 가 있습니다

pwndbg> x/60gx 0x00007a29e060e2a0
0x7a29e060e2a0 <_IO_file_jumps>:        0x0000000000000000      0x0000000000000000
0x7a29e060e2b0 <_IO_file_jumps+16>:     0x00007a29e02b22d0      0x00007a29e02b32b0
0x7a29e060e2c0 <_IO_file_jumps+32>:     0x00007a29e02b2fd0      0x00007a29e02b4370
0x7a29e060e2d0 <_IO_file_jumps+48>:     0x00007a29e02b5c00      0x00007a29e02b18d0
0x7a29e060e2e0 <_IO_file_jumps+64>:     0x00007a29e02b1530      0x00007a29e02b0b30
0x7a29e060e2f0 <_IO_file_jumps+80>:     0x00007a29e02b4940      0x00007a29e02b07f0
0x7a29e060e300 <_IO_file_jumps+96>:     0x00007a29e02b0670      0x00007a29e02a40b0
0x7a29e060e310 <_IO_file_jumps+112>:    0x00007a29e02b18b0      0x00007a29e02b1130
0x7a29e060e320 <_IO_file_jumps+128>:    0x00007a29e02b08b0      0x00007a29e02b07e0
0x7a29e060e330 <_IO_file_jumps+144>:    0x00007a29e02b1120      0x00007a29e02b5d80
0x7a29e060e340 <_IO_file_jumps+160>:    0x00007a29e02b5d90      0x0000000000000000
0x7a29e060e350: 0x0000000000000000      0x0000000000000000
0x7a29e060e360 <_IO_str_jumps>: 0x0000000000000000      0x0000000000000000
0x7a29e060e370 <_IO_str_jumps+16>:      0x00007a29e02b62a0      0x00007a29e02b5f10

_IO_str_jumps 구조체도 출력해보면, 네 번째 값에 __overflow가 정의되어 있습니다 (0x7a29e060e360+24)
__GI_IO_str_overflow를 가리키고 있습니다

pwndbg> p *(struct _IO_jump_t *)0x7a29e060e360
$30 = {
  __dummy = 0, 
  __dummy2 = 0, 
  __finish = 0x7a29e02b62a0 <_IO_str_finish>, 
  __overflow = 0x7a29e02b5f10 <__GI__IO_str_overflow>, 

떨어진 거리를 구하면 0xd8 차이납니다

pwndbg> p (0x7a29e060e360+24)-0x00007a29e060e2a0
$31 = 216

2.libc.symbols['_IO_str_overflow'] 와의 차이

_IO_str_jumps 구조체의 __overflow는 결국 __GI__IO_str_overflow를 가리킵니다. 다만 다른 점은 위치입니다
강의에서 설명하다시피, vtables의 주소가 __libc_IO_vtables 섹션 안에 있어야 합니다

위에서 구한 libc.symbols['_IO_file_jumps']+0xd8은 아래와 같이 __libc_IO_vtables 섹션에 존재합니다

pwndbg> info symbol 0x00007a29e060e2a0+0xd8
_IO_str_jumps + 24 in section __libc_IO_vtables of /lib/x86_64-linux-gnu/libc.so.6

하지만 libc.symbols['_IO_str_overflow'] 는 .text 섹션에 존재합니다

pwndbg> p _IO_str_overflow
$33 = {int (_IO_FILE *, int)} 0x7a29e02b5f10 <__GI__IO_str_overflow>
pwndbg> info symbol 0x7a29e02b5f10
_IO_str_overflow in section .text of /lib/x86_64-linux-gnu/libc.so.6

그래서 위의 것을 써야합니다.

2024.12.31. 06:32