Natas27:

一个登录节界面,查看源码。

<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas27", "pass": "<censored>" };</script></head>
<body>
<h1>natas27</h1>
<div id="content">
<? // morla / 10111
// database gets cleared every 5 min /*
CREATE TABLE `users` (
`username` varchar(64) DEFAULT NULL,
`password` varchar(64) DEFAULT NULL //这是重点,用户名和密码均不超过64个字节
);
*/ function checkCredentials($link,$usr,$pass){ //转义用户名和密码中的特殊字符,防止sql注入
$user=mysql_real_escape_string($usr);
$password=mysql_real_escape_string($pass); $query = "SELECT username from users where username='$user' and password='$password' ";
$res = mysql_query($query, $link);
if(mysql_num_rows($res) > 0){ //若查询出来的数组大于0,则验证用户名/密码成功
return True;
}
return False;
} function validUser($link,$usr){ $user=mysql_real_escape_string($usr); $query = "SELECT * from users where username='$user'";
$res = mysql_query($query, $link);
if($res) {
if(mysql_num_rows($res) > 0) {
return True;
}
}
return False;
} function dumpData($link,$usr){ $user=mysql_real_escape_string($usr); $query = "SELECT * from users where username='$user'";
$res = mysql_query($query, $link);
if($res) {
if(mysql_num_rows($res) > 0) {
while ($row = mysql_fetch_assoc($res)) { //mysqli_fetch_assoc() 函数从结果集中取得一行作为关联数组。
// thanks to Gobo for reporting this bug!
//return print_r($row);
return print_r($row,true);
}
}
}
return False;
} function createUser($link, $usr, $pass){ $user=mysql_real_escape_string($usr);
$password=mysql_real_escape_string($pass); $query = "INSERT INTO users (username,password) values ('$user','$password')";
$res = mysql_query($query, $link);
if(mysql_affected_rows() > 0){ //mysqli_affected_rows() 函数返回前一次 MySQL 操作所影响的记录行数
return True;
}
return False;
} //逻辑:查询username是否存在
if(array_key_exists("username", $_REQUEST) and array_key_exists("password", $_REQUEST)) {
$link = mysql_connect('localhost', 'natas27', '<censored>');
mysql_select_db('natas27', $link); //mysql_select_db() 函数设置活动的 MySQL 数据库。 if(validUser($link,$_REQUEST["username"])) {
//user exists, check creds
if(checkCredentials($link,$_REQUEST["username"],$_REQUEST["password"])){
echo "Welcome " . htmlentities($_REQUEST["username"]) . "!<br>"; //htmlentities() 函数把字符转换为 HTML 实体。
echo "Here is your data:<br>";
$data=dumpData($link,$_REQUEST["username"]);
print htmlentities($data);
}
else{
echo "Wrong password for user: " . htmlentities($_REQUEST["username"]) . "<br>";
}
}
else {
//user doesn't exist
if(createUser($link,$_REQUEST["username"],$_REQUEST["password"])){
echo "User " . htmlentities($_REQUEST["username"]) . " was created!";
}
} mysql_close($link);
} else {
?> <form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password" type="password"><br>
<input type="submit" value="login" />
</form>
<? } ?>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

natas28-sourcecode.html

查看源码,本来想通过sql注入来获取密码,但是很难实现:
一是源码通过mysql-real-escape-string()函数对输入的用户名和密码中的特殊字符进行了转义,以防止sql注入;
二是想要绕过的话也很困难:$password使用''括起来了,无法用like wildchar和number绕过。
(参见https://www.sqlinjection.net/advanced/php/mysql-real-escape-string/)

继续分析,总结流程如下:
Receive Input -> Check if user exist -> if exist check credentials -> show data.
Receive Input -> check if user exist -> if dosen't -> create user.
即后台获取到用户输入的用户名/密码后,首先查询此用户名是否存在,如果存在,验证密码并显示数据;如果不存在,创建用户。

同时,验证用户名/密码是否正确也仅仅是看返回数组是否>0。

很容易联想到,如果我们插入一个和目标账户相同的行,即使我们不知道密码,checkCredentials()函数查找的结果数组也会>0并返回true,接着dumpData()函数就可能回显真正的用户与密码了。(注意这里只会回显一行,虽然dumpData()里面是个while循环,但里层直接return print_r($row,true)了)

插入数据需实现两点:
一是validUser()函数查找不到用户;
二是存储后的username要和目标username相同,密码自己定。

那么如何实现插入的用户名既和目标username相同,又使validUser()函数查找不到呢?

这里还要参考两个mysql里面的知识点 :

一是字符串存储时若发生“溢出”,mysql会自动truncate到最大宽度;
二是空格在varchar里面会被自动删除。

所以,正确的插入为“natas28+超过64字节的连续空格+xxx”(注意,后面的xxx是必须的,因为在mysql中'natas28'='natas28+空格'),密码随意,可以为空。

比较username时mysql并不会对提交的username进行truncate,所以判断用户名不存在,开始新建用户名和密码。一旦开始存储,就会发生溢出/截取,导致出现两个username同为‘natas28’的行。接着返回登录界面,输入natas28+密码。找寻操作会返回刚刚插入的数组(>0),所以查询成功,回显用户名和密码,这时回显的就是第一个nata28那行,即我们要获得的flag。

首先输入
用户名:natas28                                                             xxx
密码:aaa
返回如下:

接着返回登录页面,重新输入
用户名:natas28
密码:aaa
返回如下:

flag:JWwR438wkgTsNKBbcJoowyysdM82YjeF

另外,网友还给出了一个利用开头“5分钟重置”来进行注入的例子,思路是一样的,实现方法不一样:

源码中提示了每五分钟将会清除一次数据
这个清除的过程应该是全部清空->写入username=natas28,password=xxx记录
如果卡在全部清空和写入之间抢先提交username=natas28,password=”的记录,那么由于提交时没有检测到natas28,将会写入我们的记录;等服务器重新写入本来的natas28,再检索就也能显示出来了

import requests
data={'username':'natas28','password':''}
auth=requests.auth.HTTPBasicAuth('natas27','55TBjpPZUUJgVP5b3BnbG6ON9uDPVzCJ')
while 1:
re=requests.post("http://natas27.natas.labs.overthewire.org",auth=auth,data=data)
if 'Wrong password' not in re.text:
print(re.text)
break

用脚本不断发起请求有几率正好插入其中,但是数据库重置的时间很难把握,我们很难实现恰好在数据库重置的那个时刻将我们自己的用户名/密码写入数据库。如下图所示,程序跑了1.5小时,共发送了1311次请求,始终没有跑出结果。(也可能是我网速过慢的原因,如果是在内网跑,估计成功的可能性大一点)

参考:

https://www.cnblogs.com/liqiuhao/p/6906474.html
https://blog.csdn.net/baidu_35297930/article/details/99732206?utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/whklhhhh/article/details/77484274?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://www.sqlinjection.net/advanced/php/mysql-real-escape-string/
https://blog.csdn.net/lyover/article/details/50224821

Natas27 Writeup(mysql溢出截断漏洞)的更多相关文章

  1. Oracle MySQL Server 安全漏洞

    漏洞名称: Oracle MySQL Server 安全漏洞 CNNVD编号: CNNVD-201401-317 发布时间: 2014-01-22 更新时间: 2014-01-22 危害等级: 中危  ...

  2. Oracle MySQL Server 拒绝服务漏洞

    漏洞名称: Oracle MySQL Server 拒绝服务漏洞 CNNVD编号: CNNVD-201401-316 发布时间: 2014-01-22 更新时间: 2014-01-22 危害等级: 中 ...

  3. mysql代码执行漏洞

    mysql  (5.7, 5.6, 和 5.5版本)的所有默认安装配置,包括最新的版本,攻击者可以远程和本地利用该漏洞.该漏洞需要认证访问MYSQL数据库(通过网络连接或者像phpMyAdmin的we ...

  4. Natas26 Writeup(PHP反序列化漏洞)

    Natas26: 打开页面是一个输入坐标点进行绘图的页面. <html> <head> <!-- This stuff in the header has nothing ...

  5. Java上传截断漏洞的解决方案

    文件上传漏洞解决方案 1. 最有效的,将文件上传目录直接设置为不可执行,对于Linux而言,撤销其目录的'x'权限:实际中很多大型网站的上传应用都会放置在独立的存储上作为静态文件处理,一是方便使用缓存 ...

  6. Natas33 Writeup(Phar反序列化漏洞)

    Natas33: 又是一个上传文件的页面,源码如下: // graz XeR, the first to solve it! thanks for the feedback! // ~morla cl ...

  7. Natas24 Writeup(strcmp绕过漏洞)

    Natas24: 一个登录页面,查看源码,发现关键代码: if(array_key_exists("passwd",$_REQUEST)){ if(!strcmp($_REQUES ...

  8. 利用logrotate将mysql log截断

    https://blog.pythian.com/mysql-log-rotation/ 1.授权用户 CREATE USER 'log_rotate'@'localhost' IDENTIFIED ...

  9. 2017年第二届广东省强网杯线上赛WEB:Musee de X writeup(模板注入漏洞)

    目录 解题思路 总结 解题思路 拿到手上,有四个页面 首先按照题目要求执行,尝试注册一个名为admin的账户 这种情况,路径都给出来了,很可能就是目录遍历或者文件上传了 回到初始界面,点击链接here ...

随机推荐

  1. unittest(7)-作业- 全局变量传递cookie

    全局变量存储cookie 测试类中有多个测试函数 # 1.http_requset.py import requests class HttpRequest: def http_request(sel ...

  2. 深度学习之TensorFlow安装与初体验

    深度学习之TensorFlow安装与初体验 学习前 搞懂一些关系和概念 首先,搞清楚一个关系:深度学习的前身是人工神经网络,深度学习只是人工智能的一种,深层次的神经网络结构就是深度学习的模型,浅层次的 ...

  3. python 前端素材提供

    小图标素材:http://fontawesome.dashgame.com/

  4. react-native保存图片Android实现方法

    /图片的路径格式为远程请求, 例如:'http://xxx:8080/image.jpg' import { Platform, PermissionsAndroid, NativeModules } ...

  5. 将java project打包成jar包,web project 打包成war包的几种演示

    将java项目打包成jar 第一种:MyEclipse将java项目打包成jar. 1,右击项目,选择export . 2,点击Java,选择JAR file . 3,在JAR file文本中浏览打包 ...

  6. 《HelloGitHub》第 47 期

    兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...

  7. Spring Boot从入门到精通(五)多数据源配置实现及源码分析

    多数据源配置在项目软件中是比较常见的开发需求,Spring和Spring Boot中对此都有相应的解决方案可供大家参考.在Spring Boot中,如MyBatis.JdbcTemplate以及Jpa ...

  8. Leetcode1353_最多可以参加的会议数目

    题目地址 给定n个会议时间区间,会议不用全程参加,问最多能参加的数目. 时间区间按左端点排序,扫一遍,每一天把当天开始的区间结束时间加入,同时把这一天之前结束的区间删掉,然后贪心从最小堆取出结束时间的 ...

  9. 聊聊RabbitMQ那一些事儿之一基础应用

    聊聊RabbitMQ那一些事儿之一基础应用 Hi,各位热爱技术的小伙伴您们好,今年的疫情害人啊,真心祝愿您和您的家人大家都平平安安,健健康康.年前到现在一直没有总结点东西,写点东西,不然久了自己感觉自 ...

  10. swagger 以及swaggerUI使用的步骤

    1.swagger,可以这么理解swagger是接口规范.Rest Api 传递参数的除了get请求外,put post,需要传递json.或者就是直接都通过传递json到后台 这里主要介绍一下spr ...