1. introduction
之前讲了那么多问题,包括shellcode
和memory errors
,现在终于到了讲利用场景(shellcode + memory errors结合)的时候了!
所谓利用场景,就是思考目标哪个位置会有漏洞,如果有了漏洞(栈溢出,etc),你如何利用这个漏洞来实现攻击(破坏目标,泄露信息,夺取控制权,etc)
先从高手Phineas Fisher
的事迹开始说起,这位哥们在2016年黑了Hacking Team(是一家帮助政府针对新闻记者,激进分子,政府中的反对派以及其他的对政府可能造成的威胁因素进行入侵和监控的公司)
,并讲解了他是如何入侵的。
从他的入侵过程中,我们可以学习到利用场景的思路。
1. External reconnaissance. 外部侦察,即观察目标的运行逻辑
Look at the program. Understand it. How does it work? What might be potential vulnerable functionality?
2. Gaining a foothold. 站稳脚跟,即挖目标的洞
Find the teenies tiniest security hole. Exploit it!
3. Internal reconnaissance. 内部侦察,即思考挖的洞有什么用
What does your vulnerability change in the program state? What else does this allow you to do?
4. Gaining influence. 获得影响(指利用漏洞获得更多的目标信息)
Exploit the security hole(s) ,your initial corruption opened up.
5. Total compromise. 完全控制,一步一步完全控制目标!
Repeat steps 3 and 4 until the system is totally broken.
6. Gloating. 笑😀
Get and submit the flag!
这也是现在普遍的渗透测试思路!
ps:渗透测试的时候要注意道德准测,不要做违法的事!
2. Exploitation Scenarios
现在具体说说有哪些利用场景⑧
2.1 Control Flow Hijack to Shellcode
第一个就是控制流夹持到shellcode
参考例子:
void bye1() { puts("Goodbye!"); }
void bye2() { puts("Farewell!"); }
void hello(char *name, void (*bye_func)())
{
printf("Hello %s!\n", name);
bye_func();
}
int main(int argc, char **argv)
{
char name[1024];
gets(name);
srand(time(0));
if (rand() % 2) hello(name, bye1);
else hello(name, bye2);
}
该例子中,因为有memory errors
问题,导致我们可以在栈中写入shellcode
,如果我们知道栈地址
,就能实现利用!
诸如各种栈保护,破解方法与https://wsxk.github.io/memoryerror/类似,这里不过多解释
2.2 Vulnerability Side-Effects
A vulnerability in a program generally has more effects than just hijacking control flow.
参考例子:
#include <seccomp.h>
#include <assert.h>
int main(int argc, char **argv) {
struct {
char shellcode[128];
int sandboxed;
} program;
program.sandboxed = 1;
gets(program.shellcode);
if (program.sandboxed) {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_KILL);
assert(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0) == 0);
assert(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0) == 0);
assert(seccomp_load(ctx) == 0);
}
((void(*)())program.shellcode)();
}
该场景中,可以通过memory errors
漏洞来写入shellcode
,同时也可以修改程序的沙箱保护!
再来看一个例子:
int main(int argc, char **argv) {
struct {
char shellcode[128];
char *shellcode_copy;
} program;
data.shellcode_copy = malloc(128);
gets(data.shellcode);
strcpy(data.shellcode_copy, data.shellcode);
}
这个场景中,如果溢出导致shellcode_copy
被修改,那么该程序会在main
返回前就崩溃!
2.2.1 seccomp
seccomp
是linux内核提供的一个安全机制,允许进程自己限制 哪些系统调用可以被执行
核心的函数如下:
ctx=seccomp_init();//创建scmp_filter_ctx过滤器对象
//参数可以是 SCMP_ACT_KILL(0)(对于未允许的系统调用,终止进程 白名单) 或 SCMP_ACT_ALLOW(0x7fff0000 对于未允许的系统调用,允许执行,黑名单)
seccomp_rule_add(ctx,0x7FFF0000,syscall_num,0);// 添加规则,这里表示允许syscall_num的调用,0表示不对系统调用的参数做限制
seccomp_load(ctx);//将规则加载到内核,使其生效
如果程序有内存错误允许你控制程序不执行seccomp,就可以绕过这个限制!
如果只允许你使用2个系统调用,首选chmod,任意一个看能否让程序顺利执行
顺便给出执行chmod
的汇编
""" /* push b'/flag\x00' */
mov rax, 0x101010101010101
push rax
mov rax, 0x101010101010101 ^ 0x67616c662f
xor [rsp], rax
/* call open('rsp', , 'rdx') */
push SYS_chmod /* 90 */
pop rax
mov rdi, rsp
mov rsi, 511/* 0777 */
syscall
"""
2.3 JIT Spraying
JIT Spraying
可以用来绕过DEP和ASLR(概率)
保护。
Modern higher-level languages (JavaScript, Java, Lua, Python, etc)
utilize Just in Time Compilation.
1. Code is written in JavaScript.
2. At runtime, necessary code is compiled to binary code.
3. Binary code executes very fast.
Of course, this means that an attacker that can inject
higher-level code can influence the resulting native code...
... including immediate values stored!
对于alsr
,这不是一个完全的解决方案,但是可以部分解决!
核心思路是在很多页都写入你想执行的代码!这样爆破的概率就大大提高了