# TASK:

​ 编写 IDA 脚本,不依赖版本号的条件下,利用二进制特征,在 openssl 的 libssl.so 中检查 CVE-2015-0207 和 CVE-2014-3507 是否被修补

要求:idc 和 python 两个版本都写一下,这个就是把 libssl.so 拖进 ida,然后运行你的脚本,然后弹窗或者输出有没有那两个 cve 存在

参考链接:https://www.hex-rays.com/products/ida/support/idadoc/162.shtml 按字母顺序排列的 IDC 函数列表

不依赖版本号,就是使用 ida 通用的函数,

# 前置:diff dapatch

# 对于数据的定义

ida 各版本通用的是划分为,整数 long,字符串 string,以及浮点数,而不做具体的划分。或者使用无定形的关键字 auto,定义一个变量。但是在模块中,我们还是要局部变量先声明。可以在任何地方都可以定义定义一个全局变量,关键字为 extern,但是不能在声明的同时,进行赋值。

# 运算

idc 不支持复合赋值运算,比如 i+=2 这样,但是支持三元运算符(?:)。

# 数据处理:

idc 这种脚本程序,最重要的就是数据的获取以及处理,idc 库提供了相关的数据获取与处理的函数

1
2
3
4
5
6
7
8
9
10
读取内存数据
long Byte(long addr);
long Word(long addr);
long Dword(long addr);
修改内存数据
void Patchbyte(long addr);
void Patchword(long addr):
void PatchDword(longword);
//修改数据的时候,如果提供的数据长度不匹配,从低地址开始有效
bool isLoaded(long addr); //地址是否包含有效数据

# 用户交互 —— 输入输出

image-20220629233503199

所以物品们尽量使用 Message 函数进行输出 ma ?

# 处理函数

1
2
3
4
5
6
7
8
9
//获取目标地址 *所在* 函数的名字
string GetFunctionName(long addr); //如果addr不属于一个函数,则返回一个空字符串
long NextFunction(long addr); //返回addr的下一函数的起始地址,失败返回-1
long PrevFunction(long addr); //返回addr的之前距离最近的函数的起始地址,失败返回-1
long LocByName(string name); //根据名字查找函数的起始地址

//宏定义,非法地址 BADADDR
//交叉引用

# task1:CVE-2015-0207

1
2
3
4
5
6
7
8
9
10
11
-- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
int dtls1_listen(SSL *s, struct sockaddr *client)
{
int ret;

+ /* Ensure there is no state left over from a previous invocation */
+ SSL_clear(s);
+
SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
s->d1->listen = 1;

检测是否修复漏洞,就是看看 dtls1_listen 函数是否调用了 SSL_clear 函数。

定位到 dtls1_listen 函数的位置,遍历他的每一条指令,筛选出函数调用指令的交叉引用,所以我们需要便利的同时进行排除选择,检查交叉引用的返回值,筛选出 fl_CN 或者 fl_CF 类型的交叉引用。然后判断,调用函数的名称是否为 SSL_clear.

idc 脚本

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
#include <idc.idc>
static main(){
auto func,end,target,inst,name,flags,xref;
flags = SEARCH_DOWN | SEARCH_NEXT;
Message("now ,let's begin!\n\n\n*********************\n");
func = LocByName("dtls1_listen");

if(func == BADADDR){
Warning("Sorry we cannnot find dtls1_listen in the database!");

}
else {
end = GetFunctionAttr(func,FUNCATTR_END);
name = Name(func)
for(inst = func; inst <end;inst = FindCode(inst,flags)){
for (target = Rfirst(inst);target != BADADDR;target = Rnext(inst,target)){
xref = XrefType();
if(xref == fl_CN || xref == fl_CF){
Message("%s calls %s from 0x%x\n",name ,Name(target),inst);
if(target == LocByName("SSL_clear")){
Message("this database hax beens patched!");
return ;
}
}

}
}
}
}

# task2:CVE-2014-3507

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
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -616,6 +616,9 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
msg_hdr->msg_len > dtls1_max_handshake_message_len(s))
goto err;

+ if (frag_len == 0)
+ return DTLS1_HM_FRAGMENT_RETRY;
+
/* Try to find item in queue */
memset(seq64be,0,sizeof(seq64be));
seq64be[6] = (unsigned char) (msg_hdr->seq>>8);
@@ -693,7 +696,12 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
goto err;
}

- pqueue_insert(s->d1->buffered_messages, item);
+ item = pqueue_insert(s->d1->buffered_messages, item);
+ /* pqueue_insert fails iff a duplicate item is inserted.
+ * However, |item| cannot be a duplicate. If it were,
+ * |pqueue_find|, above, would have returned it and control
+ * would never have reached this branch. */
+ OPENSSL_assert(item != NULL);
}

return DTLS1_HM_FRAGMENT_RETRY;
@@ -751,7 +759,7 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
}
else
{
- if (frag_len && frag_len < msg_hdr->msg_len)
+ if (frag_len < msg_hdr->msg_len)
return dtls1_reassemble_fragment(s, msg_hdr, ok);

if (frag_len > dtls1_max_handshake_message_len(s))
@@ -780,7 +788,15 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
if ( item == NULL)
goto err;

- pqueue_insert(s->d1->buffered_messages, item);
+ item = pqueue_insert(s->d1->buffered_messages, item);
+ /* pqueue_insert fails iff a duplicate item is inserted.
+ * However, |item| cannot be a duplicate. If it were,
+ * |pqueue_find|, above, would have returned it. Then, either
+ * |frag_len| != |msg_hdr->msg_len| in which case |item| is set
+ * to NULL and it will have been processed with
+ * |dtls1_reassemble_fragment|, above, or the record will have
+ * been discarded. */
+ OPENSSL_assert(item != NULL);
}

return DTLS1_HM_FRAGMENT_RETRY;

这个相比较第一个就复杂一些,影响版本为小于 1.0.1

Edited on

Give me a cup of [coffee]~( ̄▽ ̄)~*

dreamcat WeChat Pay

WeChat Pay

dreamcat Alipay

Alipay

dreamcat PayPal

PayPal