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
|
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define CURL_STATICLIB
#include <curl/curl.h>
// --- From curl/lib/curlx/dynbuf.h ---
struct dynbuf {
char *bufr;
size_t leng;
size_t allc;
size_t toobig;
};
#define DYN_DOH_RESPONSE 3000
// --- From curl/lib/curlx/dynbuf.c ---
void curlx_dyn_init(struct dynbuf *s, size_t toobig)
{
s->bufr = NULL;
s->leng = 0;
s->allc = 0;
s->toobig = toobig;
}
void curlx_dyn_free(struct dynbuf *s)
{
free(s->bufr);
s->bufr = NULL;
s->leng = 0;
s->allc = 0;
}
CURLcode dyn_nappend(struct dynbuf *s, const unsigned char *mem, size_t len)
{
size_t idx = s->leng;
size_t a = s->allc;
size_t fit = len + idx + 1;
if(len > s->toobig - idx - 1) {
return CURLE_TOO_LARGE;
}
if(!a) {
a = fit;
}
else {
while(a < fit)
a *= 2;
}
if(a != s->allc) {
void *p = realloc(s->bufr, a);
if(!p) {
curlx_dyn_free(s);
return CURLE_OUT_OF_MEMORY;
}
s->bufr = p;
s->allc = a;
}
if(len)
memcpy(&s->bufr[idx], mem, len);
s->leng = idx + len;
s->bufr[s->leng] = 0;
return CURLE_OK;
}
CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
{
return dyn_nappend(s, (const unsigned char *)mem, len);
}
size_t curlx_dyn_len(const struct dynbuf *s)
{
return s->leng;
}
// --- From curl/lib/doh.h ---
struct doh_request {
unsigned char req_body[256 + 16];
void *req_hds;
struct dynbuf resp_body;
size_t req_body_len;
int dnstype;
};
// 这是从doh.c复制的漏洞函数
size_t doh_probe_write_cb(char *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct doh_request *doh_req = (struct doh_request *)userp;
if(!doh_req)
return -1; // CURL_WRITEFUNC_ERROR
// 漏洞点:curlx_dyn_addn被调用时传入环绕后的realsize值,可能非常大
if(curlx_dyn_addn(&doh_req->resp_body, contents, realsize))
return 0;
return realsize;
}
int main(void)
{
struct doh_request doh_req;
size_t size = 1;
size_t nmemb = (size_t)-1; // 这将导致整数溢出
char *contents = "A";
printf("使用以下参数模拟调用doh_probe_write_cb:\n");
printf("size = %zu\n", size);
printf("nmemb = %zu\n", nmemb);
// 初始化动态缓冲区
curlx_dyn_init(&doh_req.resp_body, DYN_DOH_RESPONSE);
// 此调用将崩溃,证明漏洞存在
doh_probe_write_cb(contents, size, nmemb, &doh_req);
// 这部分不会被执行到
printf("此消息不应被打印。\n");
curlx_dyn_free(&doh_req.resp_body);
return 0;
}
|