ZINO
HomeResearchBlogTagsPlaygroundStack
⌘K

레드팀 · AI 자동화 · 시스템 엔지니어링

직접 만들고, 실험하고, 기록한다

개인정보처리방침·이용약관

© 2026 ZINO LAB

블로그글 아카이브

글, 노트, 기술 문서

연구 노트, 구현 로그, 실험 및 실무형 글을 모아둔 아카이브입니다.

항목
472
current results
Filter
없음
active tag
Search
키워드 없음
current query
AllSecurityWebDevOpsEtc
태그 둘러보기
[🥉 Bronze 4] RSA-2048 을 아홉 가지로 두들기고 돌아오니 답은 소스에 있었다 — DreamHack fakeday revenge 풀이
blog

[🥉 Bronze 4] RSA-2048 을 아홉 가지로 두들기고 돌아오니 답은 소스에 있었다 — DreamHack fakeday revenge 풀이

만우절에 올라온 문제. 배포본 prob.py 가 2048비트 RSA 로 flag 를 암호화하고 N, e, c 만 남기는데 소스의 flag 자리에는 가짜로 보이는 리터럴이 박혀 있다. Fermat, Pollard p-1, rho, 저지수, factordb 까지 아홉 항목을 돌려도 흠집이 없고, 설명이 가리킨 Shor 는 4099 큐빗이 필요하다. 답은 그 리터럴 자체였다.
#dreamhack#ctf#crypto+7
2026-08-22
[🥇 Gold 3] 42만 줄짜리 XOR 지옥이 사실은 행렬 한 장 — DreamHack XOR Disaster 풀이
blog

[🥇 Gold 3] 42만 줄짜리 XOR 지옥이 사실은 행렬 한 장 — DreamHack XOR Disaster 풀이

15MB짜리 disaster.py 안에 시프트·XOR 연산이 320,000줄 흩뿌려져 있고 함수 32개가 각각 8비트만 돌려준다. 세 연산 모두 자리올림이 없어 GF(2) 위에서 선형이라, 전체가 f(v) = A·v + c 라는 아핀사상 하나로 접힌다. f(0)으로 상수를, f(e_i)로 열벡터를 뽑아 257번 호출만에 256×256 행렬을 복원하고 가우스 소거 한 번으로 끝났다.
#dreamhack#ctf#crypto+7
2026-08-22
[🥈 Silver 1] main 없는 ELF — 빈 스텁 256개 중 하나가 복귀주소를 덮는다 — DreamHack No Main 풀이
blog

[🥈 Silver 1] main 없는 ELF — 빈 스텁 256개 중 하나가 복귀주소를 덮는다 — DreamHack No Main 풀이

main 도 libc 시동 코드도 없는 26KB ELF. _start 가 자기 자신을 mmap 해 .init_array 와 .fini_array 의 주소를 직접 찾아 부르고, 생성자 안 빈 스텁 256개 중 딱 하나가 스택의 복귀주소를 덮어써 진짜 검사기로 점프한다. 마지막 관문은 덧셈과 XOR 이 섞인 10개의 식 — 캐리를 상태로 든 LSB 비트 탐색으로 0.02초에 되돌렸다.
#dreamhack#ctf#reversing+5
2026-08-22
[🥉 Bronze 4] 반투명 덧칠은 지우개가 아니다 — DreamHack QR Code 풀이
blog

[🥉 Bronze 4] 반투명 덧칠은 지우개가 아니다 — DreamHack QR Code 풀이

QR 코드 위에 검은 낙서가 덮여 있다. 그런데 픽셀값이 열 종류밖에 없고 255, 63, 16, 4, 1 이라는 등비 사슬을 이룬다. 알파 75% 검정을 겹칠 때마다 밑의 밝기가 1/4 씩만 남은 흔적이다. "픽셀값이 0보다 크면 흰 모듈" 한 줄로 29x29 격자를 되살리고, 재인코딩본과 841칸 전수 대조까지 했다.
#dreamhack#ctf#misc+5
2026-08-22
[🥈 Silver 2] 상자를 16칸으로 줄인 대가 — DreamHack Nice forest picture 풀이
blog

[🥈 Silver 2] 상자를 16칸으로 줄인 대가 — DreamHack Nice forest picture 풀이

RC4 를 그대로 옮겨 놓고 S 박스만 256칸에서 16칸으로 줄인 스트림 암호다. 원소가 0에서 15 뿐이라 출력도 니블 하나여서 평문의 상위 절반이 암호문에 그대로 남고, 출력이 S 두 칸의 XOR 이라 한 칸만 가정하면 나머지가 줄줄이 강제된다. PNG 시그니처 16바이트를 겹쳐 초기 순열을 0.7초에 되찾고 4.3MB 를 통째로 복호했다.
#dreamhack#ctf#crypto+6
2026-08-21
[🥉 Bronze 2] 화면에서 지운 것은 지운 게 아니다 — DreamHack Gyul Order 풀이
blog

[🥉 Bronze 2] 화면에서 지운 것은 지운 게 아니다 — DreamHack Gyul Order 풀이

감귤 주문 관리 앱의 주문 목록에 세 건이 들어 있는데 화면에는 두 건만 뜬다. 세 번째 항목만 isVisible 이 false 라 렌더 루프에서 걸러질 뿐, 문자열은 classes3.dex 상수풀에 그대로 남아 있다. jadx 로 3분, smali 한 바이트를 뒤집어 실기기에 다시 올리면 화면에서도 보인다.
#dreamhack#ctf#reversing+7
2026-08-21
[🥇 Gold 3] 자릿수를 뒤집은 소수 두 개 — DreamHack Triple Combination 풀이
blog

[🥇 Gold 3] 자릿수를 뒤집은 소수 두 개 — DreamHack Triple Combination 풀이

256비트 소수 p, q, r 을 2의 256제곱 진법 자릿수로 늘어놓아 만든 768비트 소수 a 와 b 는 서로 자릿수를 뒤집은 쌍이다. 그러면 2의 512제곱 빼기 1 로 나눈 나머지에서 두 소수가 같은 값으로 접히고, N 은 그 값의 제곱이 된다. 2의 512제곱 빼기 1 은 서로 다른 소수 13개로 완전분해되니 제곱근 8192개를 전부 만들어 걸러내면 된다. 전체 0.1초.
#dreamhack#ctf#crypto+5
2026-08-21
[💠 Platinum 2] 플래그를 반으로 쪼개 세 번 암호화하면 — DreamHack fl and ag 풀이
blog

[💠 Platinum 2] 플래그를 반으로 쪼개 세 번 암호화하면 — DreamHack fl and ag 풀이

68바이트 플래그를 34바이트씩 fl과 ag로 자른 뒤 fl, ag, 그리고 원본 flag를 같은 RSA 키로 전부 암호화해 공개한 문제. 평문 사이에 남은 일차 관계를 비 하나로 접어 Franklin-Reiter 관련 메시지 공격을 태우고, 거기서 나온 비를 2차원 격자 축약으로 다시 두 조각으로 펴서 0.9초 만에 플래그를 복원한 과정을 정리했다.
#dreamhack#ctf#crypto+6
2026-08-21
[💠 Platinum 3] 한글 격자가 통째로 2D 바이트코드 — DreamHack 나랏말싸미 풀이
blog

[💠 Platinum 3] 한글 격자가 통째로 2D 바이트코드 — DreamHack 나랏말싸미 풀이

한글만 빽빽한 텍스트 파일과 C++ 바이너리 하나가 배포된다. 바이너리는 그 파일을 53행 34열 격자로 읽어 초성을 명령, 중성을 이동 방향, 종성을 피연산자로 해석하는 2D VM 이었다. 격자를 디스어셈블해 보니 좌상단 6x6 이 소수 스도쿠 퍼즐판이고, 빈칸 17개가 곧 입력 17바이트였다.
#dreamhack#ctf#reversing+6
2026-08-20
[🥈 Silver 1] sorted() 가 지운 것과 못 지운 것 — DreamHack Amo's gift 풀이
blog

[🥈 Silver 1] sorted() 가 지운 것과 못 지운 것 — DreamHack Amo's gift 풀이

800 미만 소수 139개마다 sorted([p % i, q % i]) 를 흘려 주는 2048비트 RSA 문제. 정렬 때문에 어느 쪽이 p 인지는 사라지지만 두 값의 합은 그대로 남는다. 139개 소수에서 (p+q) mod i 를 모아 CRT 로 p+q 를 복원하고, 이차방정식 근으로 N 을 분해했다.
#dreamhack#ctf#crypto+3
2026-08-20
[🥉 Bronze 2] 분기 미로 뒤에 숨은 상수 한 줄 — DreamHack Labyrinth 풀이
blog

[🥉 Bronze 2] 분기 미로 뒤에 숨은 상수 한 줄 — DreamHack Labyrinth 풀이

14KB 짜리 stripped PIE 하나가 전부인 리버싱 문제. ptrace 안티디버깅과 시드 %7 로 갈라지는 분기 미로가 겹겹이 깔려 있지만, 정답 입력은 .rodata 의 32바이트를 0x30 으로 XOR 한 것이 전부였다. flag 생성기까지 파이썬으로 재구현해 바이너리 출력과 바이트 단위로 대조했다.
#dreamhack#ctf#reversing+6
2026-08-20
[🥇 Gold 2] 위수가 p 인 곡선 위의 ECDH — DreamHack Not So Smart 풀이
blog

[🥇 Gold 2] 위수가 p 인 곡선 위의 ECDH — DreamHack Not So Smart 풀이

곡선의 위수가 소수 p 자신과 같으면(트레이스 1) 타원곡선 이산로그가 p진수의 덧셈으로 내려앉는다. SageMath 없이 Q_p 산술을 직접 구현한 Smart's attack 으로 256비트 ECDLP 를 0.8초에 풀고, 거기서 얻은 ECDH 공유비밀로 AES-CBC 를 벗겨 플래그를 꺼냈다.
#dreamhack#ctf#crypto+5
2026-08-20
[🥈 Silver 1] nonce 절반이 새면 ECDSA 개인키는 1.8초 만에 나온다 — DreamHack [LINE CTF 2021] babycrypto4 풀이
blog

[🥈 Silver 1] nonce 절반이 새면 ECDSA 개인키는 1.8초 만에 나온다 — DreamHack [LINE CTF 2021] babycrypto4 풀이

서명 20개와 각 서명의 nonce 상위 16비트가 주어지는 ECDSA 문제. 사이드채널 유출이라는 말에 반사적으로 격자를 떠올리기 쉽지만, 데이터를 먼저 재 보면 nonce 자체가 32비트뿐이라 미지수가 16비트밖에 안 남는다. 서명 하나로 65,536개의 개인키 후보를 만들고 나머지 19개 서명으로 걸러 내면 후보가 정확히 하나로 줄어든다. 복구한 키는 직접 구현한 secp160r1 과 SageMath 두 곳에서 공개키를 다시 만들어 서명 20개를 전부 검증했고, 정석인 Hidden Number Problem 격자로도 같은 값이 나오는지 LLL 로 교차 확인했다.
#dreamhack#ctf#crypto+7
2026-08-20
[🥇 Gold 4] WAT 정독으로 68바이트 되돌리기 — DreamHack Wasm rev for beginners 풀이
blog

[🥇 Gold 4] WAT 정독으로 68바이트 되돌리기 — DreamHack Wasm rev for beginners 풀이

브라우저에서 도는 wasm-bindgen 산출물 하나가 전부인 리버싱 문제. wabt 으로 WAT 을 뽑아 check 함수를 읽으면 68바이트 XOR 키와 x*13+37 아핀 변환 두 단계가 전부다. 13 의 mod 256 역원 197 로 브루트포스 없이 플래그를 한 번에 복원했다.
#dreamhack#ctf#reversing+5
2026-08-20
[🥇 Gold 4] 지그재그로 접힌 플래그 — DreamHack quilt 풀이
blog

[🥇 Gold 4] 지그재그로 접힌 플래그 — DreamHack quilt 풀이

배포된 quilt는 플래그를 검사하는 프로그램이 아니라 플래그를 그림으로 굽는 인코더였다. /dev/urandom 192바이트 한복판에 인자를 그대로 얹고, 6비트씩 잘라 64색 팔레트로 32×32 블록을 칠한다. 되돌리는 길목에 놓인 함정은 홀수 격자행을 좌우로 뒤집는 한 줄이다.
#dreamhack#ctf#reversing+4
2026-08-20
[🥉 Bronze 1] assert 한 줄이 MISTY1 을 20비트로 — DreamHack 딸깍 풀이
blog

[🥉 Bronze 1] assert 한 줄이 MISTY1 을 20비트로 — DreamHack 딸깍 풀이

RFC 2994 순정 MISTY1 구현에 assert 한 줄이 얹혀 있다. bytes 비교가 사전식이라 128비트 키가 2^20 으로 잘리고, 그 100만 개를 전수 복호하면 DH{...} 형식 평문이 딱 하나 남는다. RFC 원문과의 기계 대조, 시험벡터 재현, C 독립 구현 교차검증까지.
#dreamhack#ctf#crypto+5
2026-08-20
[🥉 Bronze 2] 신음소리 13글자로 짠 프로그램에서 Base45 플래그 꺼내기 — DreamHack 어 형이야 풀이
blog

[🥉 Bronze 2] 신음소리 13글자로 짠 프로그램에서 Base45 플래그 꺼내기 — DreamHack 어 형이야 풀이

배포본은 확장자가 .bro 인 22KB 짜리 텍스트 하나다. 등장하는 글자가 마침표까지 합쳐 열세 종류뿐이라 난해한 프로그래밍 언어 "혀엉..." 소스라는 게 금방 드러난다. 명세대로 인터프리터를 짜서 돌리면 영문 안내문이 나오고, 그 안에 따옴표로 묶인 26글자가 하나 박혀 있다. 문제 설명이 말한 "45살" 은 시저 45가 아니라 Base45 였다.
#dreamhack#ctf#misc+7
2026-08-20
[🥇 Gold 4] MP3 프레임의 안 쓰는 1비트에 플래그를 숨기다 — DreamHack Dance in the Light 풀이
blog

[🥇 Gold 4] MP3 프레임의 안 쓰는 1비트에 플래그를 숨기다 — DreamHack Dance in the Light 풀이

배포본 main 은 복호기가 아니라 삽입기였다. MP3 프레임 헤더의 private bit 하나와 프레임 본문의 XOR 패리티를 짝지어 한 프레임에 1비트씩 심는 구조라, 복호식은 parity(body) XOR private 하나로 끝난다. 배포본을 오라클로 삼아 재삽입 결과가 output.mp3 와 바이트 단위로 같음을 확인했다.
#dreamhack#ctf#reversing+5
2026-08-20
[🥈 Silver 4] JPEG 끝 뒤의 tar.bz2 와 IEND 뒤의 AES 키 — DreamHack Gyul Box 풀이
blog

[🥈 Silver 4] JPEG 끝 뒤의 tar.bz2 와 IEND 뒤의 AES 키 — DreamHack Gyul Box 풀이

귤 사진 두 장이 전부인 포렌식 문제. 하나는 JPEG 마커가 끝난 뒤에 tar.bz2 를 달고 있었고, 다른 하나는 IEND 청크 뒤에 AES 키를 평문으로 흘리고 있었다. 상자를 네 겹 벗기면 ROT 치환과 AES-256-ECB 가 차례로 나오고, 마지막 플래그는 문자열이 아니라 그림으로 렌더돼 있다.
#dreamhack#ctf#forensics+7
2026-08-20
[🥈 Silver 4] php.ini 한 줄로 SQL Injection 이 막히던 시절 — DreamHack [CodeEngn] Malware L04 풀이
blog

[🥈 Silver 4] php.ini 한 줄로 SQL Injection 이 막히던 시절 — DreamHack [CodeEngn] Malware L04 풀이

배포 파일이 아예 없고 두 줄짜리 질문만 있다. "APM 사이트가 SQL Injection 공격을 받는 중인데 PHP 설정파일에서 어떤 옵션을 켜야 안전한가." 답은 알겠는데 근거가 얇아서, 그 옵션이 실제로 동작하는 마지막 세대인 Debian 6 (Apache 2.2 / PHP 5.3.3 / MySQL 5.1) 을 도커로 세워 Off/On 을 대조했다. 두 종류의 인젝션이 실제로 막히고, 그럼에도 숫자 파라미터와 GBK 우회는 그대로 통과한다.
#dreamhack#ctf#misc+7
2026-08-19
[🥈 Silver 1] MixColumns 하나가 빠지면 AES 는 XOR 표로 무너진다 — DreamHack locked present 풀이
blog

[🥈 Silver 1] MixColumns 하나가 빠지면 AES 는 XOR 표로 무너진다 — DreamHack locked present 풀이

25바이트 비밀번호를 검사하는 stripped ELF 안에 5x5 블록 AES 변형이 통째로 들어 있다. S-box 도 Rcon 도 진짜 AES 인데 MixColumns 만 없다. 그 하나가 빠지자 확산이 사라져 평문 바이트 하나가 암호문 바이트 하나로 그대로 대응했고, 라운드가 10 이라 열 회전마저 상쇄돼 자리 순열까지 항등이 됐다. 재구현으로 되감아 비밀번호를 복구하고, 키를 전혀 모르는 상태에서도 같은 값이 나오는 두 가지 경로를 따로 실증했다.
#dreamhack#ctf#reversing+7
2026-08-19
[🥈 Silver 1] 소수 p 의 하위 280비트만 지워졌다 — DreamHack tiny roots 풀이
blog

[🥈 Silver 1] 소수 p 의 하위 280비트만 지워졌다 — DreamHack tiny roots 풀이

RSA 소수 p 의 상위 744비트가 그대로 노출된 문제. Coppersmith 의 known-MSB 인수분해를 3x3 격자로 직접 짜서 하위 280비트를 되찾고, 순수 파이썬 LLL 만으로 0.4초 만에 n 을 쪼갠다. SageMath small_roots 와 openssl 로 교차검증까지.
#dreamhack#ctf#crypto+5
2026-08-19
[🥇 Gold 2] 두 배점 x 좌표 하나로 키 두 개 되찾기 — DreamHack Elliptic Curve Basic 풀이
blog

[🥇 Gold 2] 두 배점 x 좌표 하나로 키 두 개 되찾기 — DreamHack Elliptic Curve Basic 풀이

NIST P-256 위의 랜덤 점 P와 그 두 배점 2P를 10쌍 뽑아, 두 점의 x 좌표만 key1·key2에 대한 1차식으로 흘린다. 점도 y 좌표도 공개되지 않지만 y가 제곱으로만 등장하는 덕분에 두 x 좌표는 하나의 유리함수로 묶인다. key2를 소거해 7차 다항식을 세우고 GF(p) 근을 전부 구한 뒤, 남은 여덟 쌍으로 가짜 후보 둘을 걸러냈다.
#dreamhack#ctf#crypto+5
2026-08-19
[🥉 Bronze 2] 난해한 언어 엄랭 읽어내기 — DreamHack 엄... 풀이
blog

[🥉 Bronze 2] 난해한 언어 엄랭 읽어내기 — DreamHack 엄... 풀이

배포본은 온점과 반점, 그리고 "어" "엄" "식" 만으로 채워진 .umm 파일 한 개다. 문제 설명은 GitHub 링크 하나뿐. 엄랭(umjunsik-lang) v2 문법을 확정하고 디스어셈블러와 인터프리터를 직접 짜서 51줄을 해석했다. 공백이 곱하기라는 것과, 마지막 카운트다운 루프가 장식이 아니라 플래그의 일부라는 것이 관문이었다.
#dreamhack#ctf#misc+4
2026-08-19
[🥉 Bronze 1] 31줄 발췌본이 base64 인코더라는 걸 증명하기 — DreamHack [CodeEngn] Malware L05 풀이
blog

[🥉 Bronze 1] 31줄 발췌본이 base64 인코더라는 걸 증명하기 — DreamHack [CodeEngn] Malware L05 풀이

악성코드 소스 31줄만 주고 "무엇을 하는 함수인가"를 묻는다. 표준 알파벳 64자와 6비트 마스크가 보이니 base64 같은데, 눈으로 찍는 대신 가려진 두 줄을 채워 컴파일하고 입력 304종을 표준과 바이트 단위로 맞춰 봤다. 덤으로 이 구현이 3의 배수 아닌 길이에서 터지고 76열 규격도 어긴다는 것까지 실측했다.
#dreamhack#ctf#misc+6
2026-08-19
[🥉 Bronze 2] .rodata 247바이트가 스택 VM 바이트코드였다 — DreamHack SelfStatus 풀이
blog

[🥉 Bronze 2] .rodata 247바이트가 스택 VM 바이트코드였다 — DreamHack SelfStatus 풀이

프로그램이 자기 /proc/self/status 를 읽어 TracerPid 로 디버거를 알아채고 조용히 죽는다. 진짜 검사는 .rodata 에 박힌 247바이트를 도는 스택 VM 이 맡는데, 그 VM 은 사용자 입력을 아예 쳐다보지 않고 정답 문자열을 스스로 조립한다. 그래서 역산할 것이 없다 — VM 만 옮겨 적으면 끝난다.
#dreamhack#ctf#reversing+6
2026-08-19
[🥉 Bronze 1] 헤더에 박히는 두 바이트 — DreamHack [CodeEngn] Malware L03 풀이
blog

[🥉 Bronze 1] 헤더에 박히는 두 바이트 — DreamHack [CodeEngn] Malware L03 풀이

악성코드 소스 10줄을 던져 주고 "무엇을 하는 함수인가"만 묻는다. 모양은 인터넷 체크섬인데, 모양만 보고 답을 찍기엔 근거가 얇다. 그래서 배포본을 한 글자도 안 고치고 컴파일해 tcpdump 로 잡은 진짜 패킷의 체크섬 자리 12곳과 맞춰 봤다. 전부 일치했고, 덤으로 이 발췌본이 규격에서 어긋나는 자리 세 군데가 나왔다.
#dreamhack#ctf#misc+6
2026-08-19
[🥈 Silver 3] 2MB 바이너리에서 코드는 509바이트뿐이었다 — DreamHack Branches and Leaves 풀이
blog

[🥈 Silver 3] 2MB 바이너리에서 코드는 509바이트뿐이었다 — DreamHack Branches and Leaves 풀이

문제 설명이 시 네 줄뿐인 리버싱. 2.1MB짜리 stripped ELF를 열어 보면 코드는 509바이트고 나머지 전부가 배열로 접은 깊이 16 이진트리다. 입력 4글자가 16비트로 펴져 트리를 16번 내려가고, 그 리프 65536개가 서로 겹치지 않아서 기대값마다 역상이 정확히 하나로 정해진다.
#dreamhack#ctf#reversing+5
2026-08-19
[🥇 Gold 1] 세그폴트가 곧 정답이다 — DreamHack Nonsense 풀이
blog

[🥇 Gold 1] 세그폴트가 곧 정답이다 — DreamHack Nonsense 풀이

main 은 해시 결과인 32비트 값을 포인터로 역참조해 매번 SIGSEGV 를 낸다. .init_array 가 걸어 둔 핸들러가 폴트 주소를 정답표와 대조하고 레지스터를 고쳐 재개하므로, 판정은 main 이 아니라 폴트 24번의 주소열이 한다. 해시는 입력이 2바이트뿐이라 바이너리 자체를 dlopen 해 오라클로 쓰고 전수조사로 48글자를 복원했다.
#dreamhack#ctf#reversing+7
2026-08-19
[🥉 Bronze 1] q = nextPrime(p) 한 줄로 무너진 자작 PGP — DreamHack Pretty Good Privacy 풀이
blog

[🥉 Bronze 1] q = nextPrime(p) 한 줄로 무너진 자작 PGP — DreamHack Pretty Good Privacy 풀이

주말에 PGP를 직접 구현했다는 사람이 RSA 키의 두 소수를 붙여서 뽑았다. 그 한 줄 때문에 1023비트 모듈러스가 Fermat 인수분해 한 번에 쪼개진다. 개인키를 복원한 뒤 RFC 4880을 직접 구현해 세션키와 본문을 차례로 벗기고, 같은 키를 gpg에 물려 교차검증했다.
#dreamhack#ctf#crypto+6
2026-08-18
[💠 Platinum 3] getrandbits 가 흘린 비트로 MT19937 상태를 되찾다 — DreamHack Unbreakable 풀이
blog

[💠 Platinum 3] getrandbits 가 흘린 비트로 MT19937 상태를 되찾다 — DreamHack Unbreakable 풀이

같은 23088비트를 32비트씩, 16비트씩, 8·4·2비트씩, 마지막엔 1비트씩 흘리는 여섯 개의 MT19937. twist 도 tempering 도 GF(2) 위에서 선형이라 누출 비트 하나가 곧 1차식 한 줄이 된다. 19968개 미지수를 numpy 비트팩 소거로 풀어 상태를 복원하고, 예측한 난수로 AES 키 체인을 되감아 플래그까지 갔다.
#dreamhack#ctf#crypto+7
2026-08-18
[💠 Platinum 4] 한 프로세스에서 32비트와 64비트가 번갈아 돈다 — DreamHack conquergent 풀이
blog

[💠 Platinum 4] 한 프로세스에서 32비트와 64비트가 번갈아 돈다 — DreamHack conquergent 풀이

배포 파일은 17KB짜리 stripped ELF 하나. 32비트 i386 바이너리인데 .text 안에 retf 가 32개 박혀 있다. CS 셀렉터를 0x33 으로 밀어 넣고 far return 하는 Heaven's Gate 로, 같은 프로세스 안에서 64비트 가젯 14종을 굴려 입력 64바이트를 qword 8개 단위로 변환한다. objdump 가 dec eax 로 보여 주는 0x48 은 REX.W 접두사였다. 가젯 규약과 상수 테이블을 도구로 뽑아 세 단계 파이프라인을 복원하고, 곱셈 상수가 전부 홀수라는 점을 이용해 mod 2^64 역원으로 되감아 플래그를 복원했다.
#dreamhack#ctf#reversing+6
2026-08-18
[💠 Platinum 4] 0의 런렝스를 감마 코드로 되감기 — DreamHack Run 풀이
blog

[💠 Platinum 4] 0의 런렝스를 감마 코드로 되감기 — DreamHack Run 풀이

배포 파일은 10KB 짜리 stripped ELF 와 160KB 짜리 flag.enc 두 개뿐이다. 바이너리는 복호기가 아니라 인코더였고, 0 의 런렝스를 Elias 감마 유사 코드로 바꿔 쓰는 1810바이트짜리 루틴 하나가 전부였다. 분기 하나를 반대로 읽으면 복원본이 통째로 비트 반전된다. objdump 로 인코더를 읽고 gdb 로 못 박은 뒤 역함수를 써서 10000x10000 PNG 를 되살렸고, 복원본을 문제 바이너리에 재투입해 sha256 일치로 검증했다.
#dreamhack#ctf#reversing+6
2026-08-18
[💠 Platinum 4] 1099줄짜리 컨트랙트에서 진짜 코드는 40줄 — DreamHack dreamthereum 풀이
blog

[💠 Platinum 4] 1099줄짜리 컨트랙트에서 진짜 코드는 40줄 — DreamHack dreamthereum 풀이

드림핵 dreamthereum(플래티넘 4, 리버싱)은 256개의 더미 함수로 채운 스마트컨트랙트다. flagChecker가 flag[i+2] = f(flag[i], flag[i+1])을 강제하는 사슬 구조라 앞 두 글자만 정하면 31글자가 전부 따라 나오고, f는 "dummy<A>(<타입>)" 시그니처의 keccak256 앞 4바이트를 16으로 나눈 나머지였다. 후보 256개를 전수로 돌려 flag를 복원하고 foundry로 띄운 실제 EVM에서 flagChecker()가 true를 반환하는 것까지 확인했다.
#dreamhack#ctf#reversing+7
2026-08-17
[🥈 Silver 4] 소수를 모듈러로 쓴 제곱 PRNG에서 시드 되찾기 — DreamHack the present 풀이
blog

[🥈 Silver 4] 소수를 모듈러로 쓴 제곱 PRNG에서 시드 되찾기 — DreamHack the present 풀이

플래그를 시드로 넣은 제곱 되먹임 PRNG가 두 번째 출력만 공개한다. 모듈러가 두 소수의 곱이 아니라 512비트 소수 하나라서, 제곱근이 거듭제곱 한 번으로 계산된다. 네제곱근 후보를 전부 구하고 이차잉여 판정으로 가지를 쳐내니 남은 건 두 개뿐이었고 그중 하나가 그대로 플래그였다.
#dreamhack#ctf#crypto+6
2026-08-17
[🥈 Silver 4] 65,536은 우연이 아니었다 — DreamHack [CodeEngn] Malware L02 풀이
blog

[🥈 Silver 4] 65,536은 우연이 아니었다 — DreamHack [CodeEngn] Malware L02 풀이

악성코드 소스 62줄만 던져주고 "무엇을 공격하는가"를 묻는 문제. 요청 본문에 박힌 DAV: 네임스페이스와 SEARCH 메서드가 답을 반쯤 알려주지만, 확신은 코드가 실제로 만들어 내는 바이트를 그대로 재구성했을 때 왔다. URI 길이가 딱 65,536바이트 — 0x10000이다.
#dreamhack#ctf#misc+5
2026-08-17
[🥈 Silver 3] srand(0xBEEF) 하나로 6MB 사진을 되찾다 — DreamHack photographer 풀이
blog

[🥈 Silver 3] srand(0xBEEF) 하나로 6MB 사진을 되찾다 — DreamHack photographer 풀이

BMP 한 장을 통째로 바꿔 놓은 26KB짜리 C++ 바이너리. 시드가 time(NULL)이 아니라 상수 0xBEEF고, 바이트마다 rand()를 정확히 한 번씩만 쓰며, 세 갈래 변환이 모두 가역이다. 그 세 조건이 맞아떨어져서 역함수를 같은 순서로 한 번씩 걸면 6,220,854바이트가 그대로 돌아온다.
#dreamhack#ctf#reversing+5
2026-08-17
[🥈 Silver 1] 키스트림 1비트로 되돌린 SNOW 3G — DreamHack snow 풀이
blog

[🥈 Silver 1] 키스트림 1비트로 되돌린 SNOW 3G — DreamHack snow 풀이

20KB 짜리 스트립트 ELF 안에 3GPP 표준 스트림 암호 SNOW 3G 가 통째로 들어 있었다. 키는 "Merry-Christmas!" 로 고정이고 IV 는 우리가 넣는 입력의 앞 16바이트 — 즉 복원해야 할 값이 자기 자신을 암호화한다. 워드마다 필요한 정보가 키스트림의 최하위 1비트뿐이라는 점을 이용해 256가지만 확인하고 32글자를 되돌렸다.
#dreamhack#ctf#reversing+6
2026-08-17
[🥈 Silver 3] 프리젠터를 70번 누르면 모스부호가 된다 — DreamHack My Nervous PPT 풀이
blog

[🥈 Silver 3] 프리젠터를 70번 누르면 모스부호가 된다 — DreamHack My Nervous PPT 풀이

발표 전 긴장해서 프리젠터를 눌러댔다는 이야기와 함께 USBPcap 캡쳐 하나만 주어진다. 310개 패킷 중 실제 데이터는 무선 프리젠터가 올린 8바이트 HID 키보드 리포트 140개뿐이고, 거기 등장하는 키는 UpArrow와 DownArrow 둘뿐이다. 두 종류 신호에 눌림 간격으로 만들어진 글자 경계까지 있으니 모스부호다. 간격 히스토그램으로 19덩어리를 자르고 복호하면 플래그가 나온다.
#dreamhack#ctf#misc+6
2026-08-17
[🥉 Bronze 2] LFSR 키스트림 32비트로 시드를 되감다 — DreamHack STREME REVERIE 풀이
blog

[🥉 Bronze 2] LFSR 키스트림 32비트로 시드를 되감다 — DreamHack STREME REVERIE 풀이

32비트 LFSR 스트림 암호로 플래그 한 줄만 암호화해서 준다. 출력 비트가 그대로 다음 상태로 들어가는 구조라, 연속된 키스트림 32비트를 알면 내부 상태가 통째로 복원된다. 알려진 평문 세 글자로 24비트를 확보하고 남은 8비트만 256가지 훑은 뒤, 시프트를 32번 되감아 시드를 복원했다.
#dreamhack#ctf#crypto+5
2026-08-17
[🥇 Gold 4] 파일 커서를 656번 흩뿌린 검증기 되감기 — DreamHack fverify 풀이
blog

[🥇 Gold 4] 파일 커서를 656번 흩뿌린 검증기 되감기 — DreamHack fverify 풀이

fverify 는 fseek(SEEK_CUR) 4949번과 1바이트 fread 656번으로만 이루어진 직선 코드다. 파일 오프셋이 코드 어디에도 안 적혀 있어 objdump 출력만으로는 무엇을 검사하는지 알 수 없다. 커서 이동을 그대로 재생해 슬롯과 파일 오프셋을 다시 이어 붙이면 656바이트 정답 파일이 통째로 복원된다.
#dreamhack#ctf#reversing+5
2026-08-17
[🥈 Silver 2] 시리얼 검증 루프를 거꾸로 돌리기 — DreamHack babycmp 풀이
blog

[🥈 Silver 2] 시리얼 검증 루프를 거꾸로 돌리기 — DreamHack babycmp 풀이

SERIAL 한 줄만 받는 MFC 다이얼로그 앱. 입력 24글자를 int32 배열로 부풀린 뒤 .data 에 박아 둔 값 24개와 통째로 비교한다. 변환이 ror32 → XOR → ADD → +30000 넉 줄뿐이라 자리마다 후보가 하나로 떨어지고, 키는 .rdata 가 아니라 코드 즉치값으로 숨어 있다. 역산본은 바이너리의 루프 기계어를 Unicorn 으로 그대로 돌려 교차검증했다.
#dreamhack#ctf#reversing+6
2026-08-17
[🥉 Bronze 3] 약관 27개 조문에 숨은 36글자 — DreamHack 서비스 이용 약관 풀이
blog

[🥉 Bronze 3] 약관 27개 조문에 숨은 36글자 — DreamHack 서비스 이용 약관 풀이

hex 한 줄짜리 텍스트 파일을 되돌리면 UTF-8 이 아니라 EUC-KR 로 쓰인 이용약관이 나온다. 본문에는 "이건 플래그가 아니다" 라고 대놓고 적힌 미끼가 박혀 있고, 진짜 플래그는 한글과 구분이 안 가는 전각 ASCII 36글자로 조문 사이에 섞여 있다. NFKC 정규화가 마지막 열쇠다.
#dreamhack#ctf#misc+8
2026-08-17
[🥉 Bronze 2] 암호도 플래그도 .data 에 누워 있다 — DreamHack Gyul Brix Calculator 풀이
blog

[🥉 Bronze 2] 암호도 플래그도 .data 에 누워 있다 — DreamHack Gyul Brix Calculator 풀이

당도를 입력받는 척하는 32비트 PE 안에, 관리자 암호와 플래그가 각각 단일바이트 XOR 한 겹만 쓴 채 .data 에 나란히 누워 있다. 키가 코드 안 즉치값이라 strings 로는 아무것도 안 잡히고, 두 블롭을 키·암호문 쌍으로 넘겨짚으면 더 헤맨다. 디스어셈블리에서 0x55 와 0x77 을 읽어내면 끝난다.
#dreamhack#ctf#reversing+6
2026-08-17
[🥇 Gold 4] 5바이트 스텁 97개로 부순 건 코드가 아니라 디스어셈블러였다 — DreamHack Vernichtet 풀이
blog

[🥇 Gold 4] 5바이트 스텁 97개로 부순 건 코드가 아니라 디스어셈블러였다 — DreamHack Vernichtet 풀이

.text 전체에 `eb ff c1 ff c9` 가 97개 박혀 있다. jmp 가 자기 오퍼랜드로 뛰어드는 겹침 명령이라 선형 스윕 디스어셈블러는 실행되지도 않는 유령 명령을 보여 준다. 길이를 유지한 채 NOP 으로 덮어 코드를 되살리고, 그 안에 숨어 있던 15×15 Hidato 퍼즐을 풀어 답안 파일의 sha256 을 플래그로 받아냈다.
#dreamhack#ctf#reversing+7
2026-08-17
[🥇 Gold 3] 게임을 켜지 않고 게임 화면을 읽는다 — DreamHack My_First_Game_v0.1 풀이
blog

[🥇 Gold 3] 게임을 켜지 않고 게임 화면을 읽는다 — DreamHack My_First_Game_v0.1 풀이

Direct3D 9 로 만든 창 하나짜리 게임. 실행해 보면 배경 텍스처만 보이는데, 사실 68개 메시가 전부 두께 없는 평면이라 카메라와 같은 평면에 놓여 옆에서 보이고 있었다. 장면 데이터가 통째로 .data 에 하드코딩돼 있어 D3DXCreateMeshFVF 루프가 읽는 네 개의 배열을 직접 파싱하면 게임을 켜지 않고 68글자를 그대로 복원할 수 있다.
#dreamhack#ctf#reversing+5
2026-08-17
[🥇 Gold 1] 함수 125개짜리 4진 트라이를 되감다 — DreamHack Function Network 풀이
blog

[🥇 Gold 1] 함수 125개짜리 4진 트라이를 되감다 — DreamHack Function Network 풀이

stripped 바이너리가 64바이트 입력을 10000번 변형해 고정된 목표값과 비교한다. 변형의 종류는 .data 에 박힌 64비트 key 가 정하는데, 그 key 는 함수 포인터가 아니라 디스패처 125개로 짜인 4진 트라이를 2비트씩 32번 타고 내려가는 경로였다. 도착지인 리프 4개가 전부 전단사라 목표값에서 10000스텝을 거꾸로 감으면 입력이 그대로 나온다.
#dreamhack#ctf#reversing+6
2026-08-16
[🥈 Silver 1] 내 번호를 당첨 번호의 별칭으로 만든다 — DreamHack 45c6 풀이
blog

[🥈 Silver 1] 내 번호를 당첨 번호의 별칭으로 만든다 — DreamHack 45c6 풀이

로또 티켓을 직렬화해 쿠키에 담아 주는데, 결과 확인 페이지가 그 쿠키를 그대로 unserialize 한다. 검사는 클래스와 배열 여부 둘뿐이라 PHP 직렬화의 참조 표기 R 을 끼워 넣을 수 있고, 내 번호를 당첨 번호와 같은 zval 에 묶어 두면 추첨 결과를 쓰는 순간 양쪽이 함께 바뀐다.
#dreamhack#ctf#web+5
2026-08-16
[🥉 Bronze 2] base64 출력이 곧 명령이 된다 — DreamHack Base64 Encoder 풀이
blog

[🥉 Bronze 2] base64 출력이 곧 명령이 된다 — DreamHack Base64 Encoder 풀이

인코딩 결과를 스택 버퍼로 strcpy 하는데 길이 검사가 없다. 목적지에서 64바이트 뒤가 종료 메뉴에서 system 에 넘어가는 커맨드 버퍼라, 출력 65번째 글자부터가 그대로 명령이 된다. base64 알파벳과 4의 배수 제약을 동시에 만족하는 네 글자를 찾으면 셸이 열린다.
#dreamhack#ctf#pwn+5
2026-08-16
[🥉 Bronze 2] 연도 자릿수로 스택을 4바이트 넘긴다 — DreamHack datestring 풀이
blog

[🥉 Bronze 2] 연도 자릿수로 스택을 4바이트 넘긴다 — DreamHack datestring 풀이

sprintf 로 날짜 문자열을 조립하는데 길이 인자가 없다. 앞부분 20바이트는 고정이고 연도만 scanf("%d") 원값이 그대로 찍히므로, 12월 25일이 일요일인 8자리 연도를 찾아 넣으면 개행 한 바이트가 buf 바로 뒤 판정 변수에 정확히 떨어진다.
#dreamhack#ctf#pwn+5
2026-08-15
[🥇 Gold 3] 화이트리스트에서 빠진 옵션 하나 — DreamHack ejs@3.1.8 풀이
blog

[🥇 Gold 3] 화이트리스트에서 빠진 옵션 하나 — DreamHack ejs@3.1.8 풀이

라우트라고는 res.render에 req.query를 그대로 넘기는 한 줄이 전부다. EJS 3.1.8은 express 경로에서 settings의 view options를 키 제한 없이 옵션으로 복사하는데, CVE-2022-29078 패치가 검사를 붙인 건 세 개뿐이었다. 검사에서 빠진 escape로 컴파일 소스에 코드를 이어붙여 언인증 RCE까지 간다.
#dreamhack#ctf#web+6
2026-08-15
[🥈 Silver 3] 탭 한 글자로 지워진 admin 을 되살린다 — DreamHack My Best Friend 풀이
blog

[🥈 Silver 3] 탭 한 글자로 지워진 admin 을 되살린다 — DreamHack My Best Friend 풀이

인사만 돌려주는 express 서비스가 내부 Private API 를 SSRF 로 호출한다. admin 이라는 문자열과 퍼센트·물음표·샵을 전부 막아 놨지만, 단어 한가운데에 탭 문자를 끼우면 필터는 다른 단어로 보고 통과시키고 axios 가 URL 을 파싱하는 순간 그 탭이 사라지면서 admin 이 되살아난다. express 기본 쿼리 파서가 중복 키를 배열로 묶어 주는 성질까지 얹으면 플래그가 떨어진다.
#dreamhack#ctf#web+6
2026-08-15
[🥈 Silver 4] vim 스왑으로 소스를 줍고 PHP 매직 해시로 admin 로그인 — DreamHack [wargame.kr] jff3_magic 풀이
blog

[🥈 Silver 4] vim 스왑으로 소스를 줍고 PHP 매직 해시로 admin 로그인 — DreamHack [wargame.kr] jff3_magic 풀이

배포 파일이 하나도 없는 블랙박스 웹 문제. 메인 페이지 alert 이 흘린 "hint : swp" 한 줄에서 vim 스왑 파일을 주워 소스를 복구하고, and·or·union 을 전부 막는 자체 방화벽을 HAVING + REGEXP 로 우회해 admin 의 비밀번호 해시를 한 글자씩 뽑았다. 그 해시가 0e 로 시작하는 매직 해시라 PHP 의 느슨한 비교 하나로 로그인이 뚫린다.
#dreamhack#ctf#web+6
2026-08-14
[🥉 Bronze 3] 아무도 없는 테이블이 만든 무조건 참 — DreamHack Logical 풀이
blog

[🥉 Bronze 3] 아무도 없는 테이블이 만든 무조건 참 — DreamHack Logical 풀이

Flask 로그인 폼 하나짜리 문제. 비밀번호를 md5 로 굳혀 넣어 SQL 인젝션은 닫혀 있는데, 정작 users 테이블에 행이 하나도 없다. 조회가 빈 결과를 돌려주면 아이디가 빈 문자열로 떨어지고, 마지막 비교가 그 빈 문자열과 우리가 보낸 아이디를 맞대 본다. 아이디를 비운 요청 한 번으로 로그인이 통과한다.
#dreamhack#ctf#web+6
2026-08-14
[🥈 Silver 4] SubBytes 하나 빼면 AES가 그냥 1차식이 된다 — DreamHack No sub please! 풀이
blog

[🥈 Silver 4] SubBytes 하나 빼면 AES가 그냥 1차식이 된다 — DreamHack No sub please! 풀이

AES의 네 연산 중 비선형인 것은 SubBytes 하나뿐이다. 그걸 빼면 남은 ShiftRows·MixColumns·AddRoundKey가 모두 GF(2) 위의 선형·아핀 연산이라 암호 전체가 M·v 더하기 상수 d 꼴로 주저앉는다. 서버는 enc(secret) 하나만 복호를 거부하지만, XOR이 enc(secret)이 되는 다른 세 블록을 대신 복호시키면 상수항이 홀수 번 남아 secret이 그대로 나온다. 복호 질의 세 번으로 끝났다.
#dreamhack#ctf#crypto+7
2026-08-14
[🥉 Bronze 3] 클리어 판정이 통째로 브라우저 안에 있다 — DreamHack 달고나 풀이
blog

[🥉 Bronze 3] 클리어 판정이 통째로 브라우저 안에 있다 — DreamHack 달고나 풀이

캔버스로 달고나 뽑기를 하는 웹 문제. 서버 코드는 24줄뿐이고 flag 를 주는 POST /api/stage5/clear 에는 검증이 한 줄도 없다. 레벨 해금은 localStorage, 90% 판정은 game.js 안. 게다가 5단계는 도형 그리는 함수 자체가 없어 브라우저로는 깰 수 없다. 게임을 건드리지 않고 API 만 한 번 때려 flag 를 받았다.
#dreamhack#ctf#web+5
2026-08-14
[🥉 Bronze 2] ShiftRows 하나 빼면 AES가 32비트 암호 네 개로 쪼개진다 — DreamHack No shift please! 풀이
blog

[🥉 Bronze 2] ShiftRows 하나 빼면 AES가 32비트 암호 네 개로 쪼개진다 — DreamHack No shift please! 풀이

AES에서 ShiftRows만 제거하면 남은 세 연산이 전부 컬럼 안에서 끝나기 때문에 128비트 블록이 독립적인 32비트 암호 네 개로 분해된다. 서버가 enc(secret) 자체는 복호화해 주지 않지만, 4바이트 청크 하나만 뒤집으면 "다른 암호문"이 되면서 나머지 세 청크는 secret 평문 그대로 돌아온다. 질의 두 번으로 16바이트를 전부 복구했다.
#dreamhack#ctf#crypto+6
2026-08-13
[🥈 Silver 2] chroot 는 cwd 를 안 옮긴다 — DreamHack cube 풀이
blog

[🥈 Silver 2] chroot 는 cwd 를 안 옮긴다 — DreamHack cube 풀이

루트 권한으로 도는 서비스가 chroot 로 자기를 가둔 뒤 RWX 버퍼에 80바이트 셸코드를 받아 실행한다. chroot 가 작업 디렉토리를 그대로 두고 간다는 점을 이용해 mkdir·chroot·chdir 반복·chroot 로 실제 루트까지 걸어 나가고 root 셸을 잡는 76바이트 셸코드를 만든다.
#dreamhack#ctf#pwnable+5
2026-08-13
[🥈 Silver 3] nonce 를 생성자에서 한 번만 만들면 개인키가 통째로 새어나온다 — DreamHack Textbook-DSA 풀이
blog

[🥈 Silver 3] nonce 를 생성자에서 한 번만 만들면 개인키가 통째로 새어나온다 — DreamHack Textbook-DSA 풀이

서명 서버의 DSA 가 nonce k 를 __init__ 에서 딱 한 번 만들어 모든 서명에 돌려 쓴다. 게다가 그 k 가 개인키의 역원이라 s 가 x 의 2차식이 되고, 서명 두 개를 빼면 2차항이 통째로 사라져 나눗셈 한 번에 개인키가 나온다. 복원한 키로 서버가 서명해 주지 않는 token 을 직접 서명해 플래그를 받는다.
#dreamhack#ctf#crypto+6
2026-08-13
[🥇 Gold 3] 비밀번호를 맞히는 대신 비교 대상을 바꾼다 — DreamHack Proton Memo 풀이
blog

[🥇 Gold 3] 비밀번호를 맞히는 대신 비교 대상을 바꾼다 — DreamHack Proton Memo 풀이

메모 편집 기능이 점으로 구분된 속성 경로를 그대로 받아 재귀 setattr 을 돈다. 내 메모 객체에서 출발해 클래스 속성인 Memo.collections 를 타고 들어가면 서버가 만들어 둔 secret 메모의 Password 객체까지 닿는다. 20바이트 난수 비밀번호를 맞히는 대신, 비교에 쓰이는 sha256 해시 한 줄을 내가 아는 값으로 덮어 flag 를 읽었다.
#dreamhack#ctf#web+5
2026-08-13
[🥉 Bronze 2] SUID gcc 와 사라진 상한 검사 — DreamHack Stupid GCC 풀이
blog

[🥉 Bronze 2] SUID gcc 와 사라진 상한 검사 — DreamHack Stupid GCC 풀이

홈 디렉토리에 쓸 권한이 없는데 root 는 그 안의 a.out 을 10초마다 실행한다. SUID 가 붙은 gcc 가 대신 파일을 써 주고, 배열 첨자가 만든 미정의 동작 때문에 gcc -O2 가 루프의 상한 검사를 통째로 지운다. 두 관문을 이어 붙여 /flag.txt 를 읽어냈다.
#dreamhack#ctf#pwnable+6
2026-08-12
[🥉 Bronze 4] 명령은 고정인데 경로가 흔들린다 — DreamHack sane-env 풀이
blog

[🥉 Bronze 4] 명령은 고정인데 경로가 흔들린다 — DreamHack sane-env 풀이

하드코딩된 system("cat ~/flag") 한 줄을 두고 프로그램은 PATH 만 표준값으로 되돌린다. 그런데 `~` 를 푸는 주체는 프로그램이 아니라 system() 이 띄우는 /bin/sh 이고, dash 의 틸드 확장은 $HOME 만 본다. 메뉴 1번으로 HOME 을 루트로 심어 cat ~/flag 를 cat //flag 로 바꿔 플래그를 읽었다.
#dreamhack#ctf#pwnable+5
2026-08-12
[🥉 Bronze 2] 스탯 창에 목표값이 통째로 적혀 있었다 — DreamHack dungeon-in-1983 풀이
blog

[🥉 Bronze 2] 스탯 창에 목표값이 통째로 적혀 있었다 — DreamHack dungeon-in-1983 풀이

스테이지마다 /dev/urandom 에서 뽑은 64비트 난수를 맞춰야 하는데, 몬스터 스탯 7개가 그 난수를 바이트 단위로 쪼개 그대로 출력해 준다. 되조립한 값을 A(+1)·B(x2) 두 버튼으로 만들면 되고, 연속 A 금지 규칙 때문에 답은 자연히 이진 전개가 된다.
#dreamhack#ctf#reversing+4
2026-08-12
[🥉 Bronze 2] 쓴 값이 다음 쓰기 주소가 된다 — DreamHack p_rho 풀이
blog

[🥉 Bronze 2] 쓴 값이 다음 쓰기 주소가 된다 — DreamHack p_rho 풀이

숫자를 하나 넣으면 배열에 저장하고, 그 값을 그대로 다음 인덱스로 삼는 무한 루프. 임의 주소 쓰기인데 주소를 직접 못 고르고 "직전에 쓴 값"이 정한다는 제약이 붙는다. buf 를 원점으로 보면 GOT 가 음수 인덱스에 있고, Partial RELRO 라 잠겨 있지도 않다. 정수 두 개로 printf@got 를 win 으로 덮어 셸을 잡았다.
#dreamhack#ctf#pwnable+6
2026-08-12
[🥉 Bronze 2] XOR 0x42 뒤에 숨은 명령 한 개 — DreamHack flag printer 풀이
blog

[🥉 Bronze 2] XOR 0x42 뒤에 숨은 명령 한 개 — DreamHack flag printer 풀이

print/id/help 세 개만 받는다던 프로그램이, 사실은 네 번째 명령을 몰래 받고 있었다. 모르는 토큰을 strdup 해서 XOR 0x42 한 뒤 스택에 조립해 둔 네 바이트와 비교하는 코드가 있고, 그걸 통과하면 print 가 art 대신 flag 를 연다. objdump 로 비교값을 읽고 gdb 로 런타임까지 확인해 한 줄로 flag 를 뽑았다.
#dreamhack#ctf#reversing+5
2026-08-11
[🥉 Bronze 3] 수량에 마이너스를 넣으면 가게가 돈을 준다 — DreamHack PEPERO 풀이
blog

[🥉 Bronze 3] 수량에 마이너스를 넣으면 가게가 돈을 준다 — DreamHack PEPERO 풀이

빼빼로 상점의 결제는 소지금에서 100 곱하기 수량을 빼는 식 하나가 전부였다. 수량의 부호를 아무도 검사하지 않아서 음수를 넣으면 뺄셈이 그대로 덧셈이 된다. 브라우저가 걸어 둔 min="0" 은 서버까지 따라오지 않는다는 걸 DevTools와 curl로 확인하고, 소지금을 2000원까지 불려 플래그를 사 온 기록.
#dreamhack#ctf#web+6
2026-08-10
[🥉 Bronze 2] MOV 계열 30바이트가 통째로 막힌 셸코드 — PUSH/POP 으로 상수를 만든다 — DreamHack No mov 풀이
blog

[🥉 Bronze 2] MOV 계열 30바이트가 통째로 막힌 셸코드 — PUSH/POP 으로 상수를 만든다 — DreamHack No mov 풀이

셸코드에 MOV 계열 바이트가 하나라도 있으면 실행을 거부하는 문제. 막힌 건 명령어 이름이 아니라 0x88~0x8C·0xA0~0xA5·0xB0~0xBF·0xC6·0xC7 라는 30개의 바이트 값이라, ModRM 과 immediate 까지 같이 걸린다. PUSH imm 으로 상수를 스택에 놓고 POP 으로 받아 42바이트 open/read/write 셸코드를 만들었다.
#dreamhack#ctf#pwnable+5
2026-08-10
[🥈 Silver 1] 로그인에 성공하는 순간 답이 바뀐다 — DreamHack Login Page 풀이
blog

[🥈 Silver 1] 로그인에 성공하는 순간 답이 바뀐다 — DreamHack Login Page 풀이

부등호도 시간지연도 블랙리스트에 막힌 블라인드 SQL 인젝션. 게다가 쿼리가 행을 반환하면 애플리케이션이 admin 비밀번호를 새로 만들어 버려서, 흔한 "참이면 로그인된다" 오라클을 쓰는 순간 답이 바뀐다. 조건이 참일 때만 MySQL 을 EXP(999) 로 죽여 HTTP 500 을 얻고, 비교는 GREATEST 항등식으로 대신해 32자 비밀번호를 225질의에 복원했다.
#dreamhack#ctf#web+5
2026-08-10
[🥇 Gold 4] 하루 넘게 걸리는 정렬을 0.2초로 건너뛰기 — DreamHack Slooooow 풀이
blog

[🥇 Gold 4] 하루 넘게 걸리는 정렬을 0.2초로 건너뛰기 — DreamHack Slooooow 풀이

배포본은 stripped PIE 하나뿐이고 코드는 1,136바이트, 데이터는 400KB다. main 이 하는 일은 그 400KB를 Stooge sort 로 정렬하고 SHA-256 을 찍는 것뿐인데, 마스터 정리를 세워 보면 10만 원소에 하루가 넘게 걸린다. 정렬 알고리즘을 실행할 필요는 없다. 비교 함수가 쓰는 비트 순열만 그대로 복원하면 결과는 파이썬 한 줄로 나온다.
#dreamhack#ctf#reversing+7
2026-08-10
[🥉 Bronze 2] 리턴주소에 8바이트 모자랄 때 — DreamHack MSNW 풀이
blog

[🥉 Bronze 2] 리턴주소에 8바이트 모자랄 때 — DreamHack MSNW 풀이

memset 은 saved RBP 직전에서 멈추고 read 는 딱 2바이트를 더 받는다. 리턴주소는 끝내 못 건드리지만 saved RBP 의 하위 2바이트만 바꿔 두면 한 층 위 Call() 의 leave;ret 이 rsp 를 우리 버퍼 위로 옮겨 준다. 좌표는 초기화하지 않은 버퍼를 그대로 출력하는 Nyang() 에서 얻는다.
#dreamhack#ctf#pwnable+7
2026-08-09
[🥇 Gold 1] 브라우저 안 wasm 한 덩어리 되돌리기 — DreamHack passcode 풀이
blog

[🥇 Gold 1] 브라우저 안 wasm 한 덩어리 되돌리기 — DreamHack passcode 풀이

HTML 한 장과 JavaScript 한 장이 전부인 문제. main.js 첫 줄에 박힌 1,984바이트 WebAssembly 모듈이 25글자 passcode를 검사한다. wabt로 뜯어 보니 256회 루프가 바이트를 전혀 섞지 않아, 25개 위치가 각자 독립된 치환 사슬을 탄다. 위치마다 256개 후보를 정방향으로 돌려 역상을 하나씩 확정했다.
#dreamhack#ctf#reversing+5
2026-08-09
[🥉 Bronze 3] ARM32 스택 오버플로로 pc 를 직접 갈아끼우기 — DreamHack Arm Training-v1 풀이
blog

[🥉 Bronze 3] ARM32 스택 오버플로로 pc 를 직접 갈아끼우기 — DreamHack Arm Training-v1 풀이

x86 의 ret 이 없는 ARM32에서는 함수 에필로그가 pop 으로 fp 와 pc 를 한꺼번에 복원한다. 저장된 lr 을 덮으면 그 값이 검사 없이 그대로 pc 가 된다. 24바이트 뒤 반환주소를 shell() 로 바꿔 system("/bin/sh") 를 호출하고, read(0, buf, 200) 가 셸 명령까지 삼켜버리는 함정은 payload 를 정확히 200바이트로 맞춰 넘긴다.
#dreamhack#ctf#pwnable+6
2026-08-09
[🥇 Gold 3] 백틱을 닫을 필요가 없었다 — DreamHack safe input 풀이
blog

[🥇 Gold 3] 백틱을 닫을 필요가 없었다 — DreamHack safe input 풀이

Jinja2 의 safe 필터가 스크립트 안 템플릿 리터럴 자리에 입력을 그대로 꽂아 준다. 백틱을 닫는 대신 달러 중괄호 하나면 코드가 실행되고, 그 자리는 문장이 아니라 표현식이라 세미콜론을 넣는 순간 전부 죽는다. Trusted Types 는 innerHTML 만 지키고 있었다.
#dreamhack#ctf#web+5
2026-08-08
[🥈 Silver 4] 쿠키 한 줄이 서버에서 eval 된다 — DreamHack node-serialize 풀이
blog

[🥈 Silver 4] 쿠키 한 줄이 서버에서 eval 된다 — DreamHack node-serialize 풀이

node-serialize 0.0.4 의 unserialize 는 "_$$ND_FUNC$$_" 로 시작하는 문자열을 eval 로 되살린다. 뒤에 괄호 두 개를 붙여 즉시실행함수로 만들면 역직렬화 시점에 코드가 돈다. 출력 채널이 없어 flag 를 Error 로 던졌고, NODE_ENV 를 안 잡아 둔 Express 가 스택 트레이스를 500 응답 본문에 그대로 실어 보내면서 플래그가 나왔다.
#dreamhack#ctf#web+5
2026-08-08
[🥇 Gold 4] 확장자는 디코딩 전, 파일 경로는 디코딩 후 — DreamHack read_flag 풀이
blog

[🥇 Gold 4] 확장자는 디코딩 전, 파일 경로는 디코딩 후 — DreamHack read_flag 풀이

GoAhead 4.1.3 은 요청 URL 의 확장자를 퍼센트 디코딩 '전' 문자열에서 뽑고, 실제로 열 파일 경로는 디코딩·정규화가 끝난 뒤에 만든다. 같은 파일을 가리키는 두 문자열이 라우팅 단계에서 갈라지는 셈이라, `flag.js%74` 한 글자로 jst 실행 핸들러를 빠져나가 정적 파일 핸들러가 .jst 원본을 그대로 뱉게 만들 수 있다.
#dreamhack#ctf#web+5
2026-08-08
[🥉 Bronze 2] 서명 없는 세션 쿠키와 초 단위로 새는 가입 시각 — DreamHack What time is it? 풀이
blog

[🥉 Bronze 2] 서명 없는 세션 쿠키와 초 단위로 새는 가입 시각 — DreamHack What time is it? 풀이

세션 토큰이 사용자 이름과 가입 시각에 2026을 곱한 값을 이어 붙인 게 전부였다. 서명이 없으니 admin의 가입 시각만 알면 쿠키를 손으로 만들 수 있고, 그 시각은 /welcome의 가입 피드가 초 단위로 그대로 뿌리고 있었다. 쿠키 한 줄을 갈아 끼워 관리자 화면의 FLAG를 회수한 기록.
#dreamhack#ctf#web+6
2026-08-08
[🥈 Silver 4] 문자열을 이어 붙여 JSON 을 만들면 — DreamHack role-admin 풀이
blog

[🥈 Silver 4] 문자열을 이어 붙여 JSON 을 만들면 — DreamHack role-admin 풀이

회원가입이 username 을 이스케이프 없이 f-string 으로 JSON 문자열에 끼워 넣는다. 따옴표를 닫고 role 키를 하나 더 넣으면 같은 객체에 role 이 두 번 들어가고, 파이썬 json 은 나중 값을 남긴다. 가입 한 번으로 관리자가 되고 /flag 가 열린다.
#dreamhack#ctf#web+5
2026-08-07
[🥇 Gold 3] 공유 라이브러리 1,257개로 만든 오토마타 — DreamHack .so what? 풀이
blog

[🥇 Gold 3] 공유 라이브러리 1,257개로 만든 오토마타 — DreamHack .so what? 풀이

main 은 64자 hex 를 받아 dlopen 과 dlsym 만으로 검사한다. .so 하나가 상태이고 f_d 가 라벨 d 인 전이라, 파일 1,257개가 통째로 결정적 오토마타다. 전이표를 objdump 로 뽑아 길이 63 경로를 찾으면 간선 19,792개 중 성공 경로가 정확히 하나 나온다.
#dreamhack#ctf#reversing+6
2026-08-07
[🥇 Gold 4] 코드보다 데이터가 열 배 큰 이유 — DreamHack Snaky 풀이
blog

[🥇 Gold 4] 코드보다 데이터가 열 배 큰 이유 — DreamHack Snaky 풀이

.text 는 1.5KB 인데 .data 가 15KB 다. 그 데이터가 25×25×25 격자였고, 입력 문자 여섯 개는 ±x ±y ±z 여섯 방향이었다. 지나온 칸이 벽으로 바뀌어 자기 몸을 밟을 수 없는 3D 뱀 미로 — 통로 107칸이 통째로 외길이라 답은 하나뿐이다.
#dreamhack#ctf#reversing+5
2026-08-07
[🥇 Gold 4] 안티디버깅이 스스로 무너지는 자리 — DreamHack ptrace_block 풀이
blog

[🥇 Gold 4] 안티디버깅이 스스로 무너지는 자리 — DreamHack ptrace_block 풀이

생성자가 AES-128 키를 만들고 main 은 그 키로 입력을 암호화해 out.txt 에 쓴다. 키를 흔드는 값은 ptrace(PTRACE_TRACEME) 의 반환값을 4096 번 곱해 만드는데, 32비트 곱셈이 넘쳐 디버거가 있든 없든 0 이 된다. 남은 건 하위 1바이트짜리 XOR 뿐이라 256 번 시도로 끝난다.
#dreamhack#ctf#reversing+6
2026-08-07
[🥈 Silver 1] 검사한 파서와 접속한 파서가 다르다 — DreamHack weird legacy 풀이
blog

[🥈 Silver 1] 검사한 파서와 접속한 파서가 다르다 — DreamHack weird legacy 풀이

URL 검사는 WHATWG new URL() 로 하고 실제 요청은 node-fetch@2 의 레거시 url.parse() 가 한다. 두 파서는 호스트명에 허용하는 글자가 달라서, 호스트 뒤에 느낌표 하나를 붙이면 검사는 localhost 로 읽고 접속은 공격자 서버로 간다. FLAG 가 담긴 Cookie 헤더가 통째로 따라온다.
#dreamhack#ctf#web+6
2026-08-07
[🥈 Silver 3] strncmp 는 8바이트를 다 보지 않는다 — DreamHack Broken Password 풀이
blog

[🥈 Silver 3] strncmp 는 8바이트를 다 보지 않는다 — DreamHack Broken Password 풀이

/dev/urandom 으로 만든 8바이트 비밀번호를 strncmp 로 검사한다. 그런데 strncmp 는 NUL 을 만나면 거기서 멈추고 같다고 답한다. 첫 바이트가 0x00 으로 나오는 1/256 만 노리면 개행 한 글자로 통과한다. 더 그럴싸해 보이는 임의 주소 쓰기 경로는 주소 유출이 없어 쓸 수 없는 미끼였다.
#dreamhack#ctf#misc+6
2026-08-07
[🥉 Bronze 1] IPv6 로 들어가서 IPv4 로 도착하기 — DreamHack Where-is-localhost 풀이
blog

[🥉 Bronze 1] IPv6 로 들어가서 IPv4 로 도착하기 — DreamHack Where-is-localhost 풀이

입력은 반드시 IPv6 여야 하고, 도착한 요청의 출발지는 반드시 IPv4 루프백이어야 한다. 서로 배타적으로 보이는 두 조건을 `::ffff:127.0.0.1` 하나가 동시에 만족시킨다. 파이썬 ipaddress 에게는 version 6 이고 리눅스 커널에게는 127.0.0.1 이기 때문이다. tcpdump 로 루프백에 흐르는 패킷이 실제로 IPv4 라는 것까지 확인했다.
#dreamhack#ctf#web+6
2026-08-07
[💠 Platinum 4] 35%만 남긴 RSA 소수를, 플래그가 문자열이라서 복원한다 — DreamHack pprintable 풀이
blog

[💠 Platinum 4] 35%만 남긴 RSA 소수를, 플래그가 문자열이라서 복원한다 — DreamHack pprintable 풀이

플래그 256자를 그대로 1024비트 소수 두 개로 쓴 RSA 문제다. p, q 의 비트 중 35.16%만 공개돼 있어 Heninger-Shacham 부분키 복원이 요구하는 57%에 한참 못 미친다. 모자란 22%를 메운 건 암호가 아니라 플래그 자체의 성질이었다 — 모든 바이트가 영문자와 밑줄, 중괄호뿐인 55종 안에 있어야 한다는 것.
#dreamhack#ctf#crypto+5
2026-08-06
[🥇 Gold 1] 빈 catch 하나가 명령어 허용목록을 통째로 삼킨다 — DreamHack node_api 풀이
blog

[🥇 Gold 1] 빈 catch 하나가 명령어 허용목록을 통째로 삼킨다 — DreamHack node_api 풀이

/show_logs 는 첫 토큰을 무조건 get 으로 갈아치워 Redis 를 읽기 전용으로 묶어 둔다. 그런데 쿼리스트링을 배열로 보내면 Array 에는 .split 이 없어 TypeError 가 나고, 본문이 비어 있는 catch 가 그걸 삼키면서 정규화 세 줄이 통째로 건너뛰어진다. 임의 Redis 명령이 열리고, 세션 저장소가 같은 Redis 라서 SET 한 번으로 내 세션이 admin 이 된다.
#dreamhack#ctf#web+6
2026-08-06
[🥇 Gold 4] 취약점을 찾는 게 아니라 막는 문제 — DreamHack PATCH-1 풀이
blog

[🥇 Gold 4] 취약점을 찾는 게 아니라 막는 문제 — DreamHack PATCH-1 풀이

122줄짜리 Flask 메모 API 에 심어 둔 취약점을 전부 패치해야 flag 가 나오는 문제. f-string SQLi 두 곳, format() 이 만들어 낸 Jinja2 SSTI 와 저장형 XSS, 메모 소유자 검증 누락, 소스에 박힌 secret_key 까지 여섯 군데를 로컬에서 재현해 놓고 고쳤다. 공격만 막고 끝나면 안 되고 SLA(기능 회귀) 도 같이 통과해야 한다.
#dreamhack#ctf#web+8
2026-08-06
[🥇 Gold 4] warnx 가 형식 문자열을 그대로 받는다 — DreamHack string 풀이
blog

[🥇 Gold 4] warnx 가 형식 문자열을 그대로 받는다 — DreamHack string 풀이

print() 가 사용자 입력을 warnx(buf) 로 그대로 넘긴다. buf 가 형식 문자열이 되니 %hn 으로 임의 주소에 쓸 수 있고, No PIE + Partial RELRO 라 GOT 주소는 고정에 쓰기까지 된다. warnx@got 를 system 으로 바꾸고 buf 에 "/bin/sh" 를 넣으면 셸이 열린다. 다만 문제가 준 libc.so.6 는 원격과 다른 빌드였다. 오프셋을 믿으면 엉뚱한 코드를 부르니 base 는 ELF 매직으로, system 은 프롤로그 바이트로 실측해서 확정했다.
#dreamhack#ctf#pwnable+5
2026-08-06
[🌱 새싹] 개인키를 통째로 주는 문제 — DreamHack Just read flag 풀이
blog

[🌱 새싹] 개인키를 통째로 주는 문제 — DreamHack Just read flag 풀이

문제가 주는 건 OpenSSH 개인키 파일 하나와 "ssh with id: dream" 한 줄이 전부다. 붙어서 flag 를 읽으면 끝이지만, 그 사이에 걸리는 게 셋 있다. 배포 zip 이 키를 0644 로 저장해서 ssh 가 키를 무시하고, 플래그 파일은 root 소유인데 그룹 비트로 열리고, 파일 끝이 개행이 아니라 CR 이라 터미널에서 플래그가 프롬프트에 덮여 사라진다. 키 컨테이너를 직접 파싱해 서버 authorized_keys 와 대조하는 것까지 해 본다.
#dreamhack#ctf#misc+5
2026-08-06
[🥇 Gold 3] 스택에 가짜 청크를 세워 malloc을 속인다 — DreamHack house_of_spirit 풀이
blog

[🥇 Gold 3] 스택에 가짜 청크를 세워 malloc을 속인다 — DreamHack house_of_spirit 풀이

임의 주소 free 하나로 스택 조각을 tcache 에 밀어 넣고, 같은 크기 malloc 으로 그 스택 주소를 되돌려받아 main 의 리턴 주소를 덮는다. glibc 2.27 의 tcache free 경로가 청크 size 자체만 보고 다음 청크는 보지 않는다는 점이 전부다. gdb 로 tcache 항목이 스택을 가리키는 순간까지 확인했다.
#dreamhack#ctf#pwn+5
2026-08-05
[🥈 Silver 4] 서명은 위조만 막는다 — DreamHack Secure Secret 풀이
blog

[🥈 Silver 4] 서명은 위조만 막는다 — DreamHack Secure Secret 풀이

플래그를 무작위 디렉터리에 숨기고 그 경로를 Flask 세션에 넣어 둔 문제. 그런데 Flask 기본 세션은 서버가 아니라 클라이언트 쿠키에 산다. 서명은 붙어 있지만 암호화는 없어서, base64와 zlib만 풀면 숨겨 둔 경로가 평문으로 나온다. secret_key는 끝까지 몰라도 된다.
#dreamhack#ctf#web+5
2026-08-05
[🥇 Gold 1] 허용된 속성 세 개로 window.CONFIG 를 만들어 낸다 — DreamHack Guest book v0.2 풀이
blog

[🥇 Gold 1] 허용된 속성 세 개로 window.CONFIG 를 만들어 낸다 — DreamHack Guest book v0.2 풀이

htmlentities 뒤에서 태그를 재조립하던 v0.1 의 버그는 그대로 두고, DOMDocument 화이트리스트만 덧붙인 방명록. 남은 것은 a 태그의 id·name·href 뿐인데 페이지 하단에 location.href = window.CONFIG.main 이 있었다. DOM Clobbering 으로 그 전역을 만들어 내고, 이를 막으려 걸어 둔 config.js 의 Object.freeze 는 경로를 한 칸 미는 RPO 로 걷어냈다.
#dreamhack#ctf#web+5
2026-08-05
[💠 Platinum 3] 실행 중에 자기 바이트코드를 갈아끼우는 .pyc — DreamHack pyc 풀이
blog

[💠 Platinum 3] 실행 중에 자기 바이트코드를 갈아끼우는 .pyc — DreamHack pyc 풀이

dis.dis 로 열면 평범한 XOR 검사처럼 보이는 .pyc 인데, 정작 그 코드는 한 번도 실행되지 않는다. ctypes 로 code object 의 co_code 버퍼를 제자리에서 XOR 해 진짜 검사 루틴을 꺼내 쓰기 때문이다. 바이트코드를 손으로 디코드해 복원하고, 4바이트 창 ROTR·XOR 변환을 뒤에서 앞으로 되감아 플래그를 뽑았다.
#dreamhack#ctf#reversing+5
2026-08-04
[💠 Platinum 3] 니블 교환·AES S-box·std::sort 로 짠 로그인 검사 되돌리기 — DreamHack rev-login 풀이
blog

[💠 Platinum 3] 니블 교환·AES S-box·std::sort 로 짠 로그인 검사 되돌리기 — DreamHack rev-login 풀이

아이디와 비밀번호를 세 단계로 검사하는 C++ 바이너리. 아이디 검사는 글자를 니블 단위로 뒤집어 옆 글자와 엮은 뒤 AES S-box 를 통과시키고, 비밀번호 검사는 S-box 를 한 번 더 누산한 다음 std::sort 로 자리 정보를 지워 버린다. 플래그는 어디에도 없고 정답 문자열의 SHA-1 이 곧 키다.
#dreamhack#ctf#reversing+6
2026-08-04
[🥇 Gold 4] 점프도 비교도 없는 VM 에서 flag 를 되뽑기 — DreamHack bitvm 풀이
blog

[🥇 Gold 4] 점프도 비교도 없는 VM 에서 flag 를 되뽑기 — DreamHack bitvm 풀이

명령이 열 개뿐인 바이트코드 VM 이 flag 를 검사한다. 분기도 비교도 산술도 없고 AND·OR·XOR 만 있다. 글자 하나를 거는 제약이 (c & A) == B 와 (c | A) == C 두 줄이라, 비트별로 쪼개면 c = (A & B) | (~A & C) 로 답이 하나씩 딱 떨어진다. 브루트포스도 솔버도 필요 없었다.
#dreamhack#ctf#reversing+6
2026-08-04
[🥉 Bronze 2] 같은 8바이트를 함수 포인터로도 문자열로도 읽는다 — DreamHack cpp_type_confusion 풀이
blog

[🥉 Bronze 2] 같은 8바이트를 함수 포인터로도 문자열로도 읽는다 — DreamHack cpp_type_confusion 풀이

Mango 객체를 Apple 로 다운캐스트하는 static_cast 한 줄이 전부다. 두 클래스의 멤버가 같은 오프셋 +8 에 놓여 있는데 한쪽은 함수 포인터, 다른 쪽은 char 배열이라 strncpy 로 8바이트를 쓰면 함수 포인터가 통째로 바뀐다. PIE 가 꺼져 있어 getshell 주소는 고정이고, strncpy 의 NUL 패딩 덕에 3바이트만 보내도 포인터가 정확히 완성된다.
#dreamhack#ctf#pwnable+6
2026-08-03
[🥈 Silver 2] 셸이 권한을 떨구기 전에 그 조건을 지워 버린다 — DreamHack Path Finder 풀이
blog

[🥈 Silver 2] 셸이 권한을 떨구기 전에 그 조건을 지워 버린다 — DreamHack Path Finder 풀이

setgid 바이너리가 system("clear") 를 부른다. 절대경로가 아니니 PATH 를 앞에서부터 훑고, 내가 심어 둔 clear 가 문제 그룹 권한으로 돈다. 그런데 setgid 비트만으로는 이게 통하지 않는다. dash 가 시작하면서 빌려온 권한을 스스로 내려놓기 때문이다. 그 방어를 무력화하는 게 바로 앞줄의 setresgid 한 줄이었다.
#dreamhack#ctf#misc+8
2026-08-03
[🥈 Silver 3] IV 자리에 키를 넣으면 복호 한 번에 키가 샌다 — DreamHack Textbook-CBC 풀이
blog

[🥈 Silver 3] IV 자리에 키를 넣으면 복호 한 번에 키가 샌다 — DreamHack Textbook-CBC 풀이

AES-CBC 서버가 IV 를 키로 재사용한다. 같은 블록을 IV 가 섞이는 자리와 안 섞이는 자리에 나란히 놓고 복호를 한 번 요청하면 두 평문의 XOR 이 그대로 IV, 즉 키가 된다. 진짜 관문은 그 요청이 unpad() 를 통과하게 만드는 꼬리 블록이었다.
#dreamhack#ctf#crypto+7
2026-08-03
[🥇 Gold 3] 4바이트 한 번으로 malloc 을 GOT 위에 착지시키다 — DreamHack house_of_force 풀이
blog

[🥇 Gold 3] 4바이트 한 번으로 malloc 을 GOT 위에 착지시키다 — DreamHack house_of_force 풀이

top 청크의 size 를 0xffffffff 로 바꾸면 malloc 은 힙이 무한히 크다고 믿는다. 그 상태로 거대한 크기를 요청하면 av->top 이 32비트 덧셈에서 되감겨 GOT 앞으로 끌려오고, 다음 malloc 은 scanf@got 를 그대로 돌려준다. 임의 쓰기는 단 한 번뿐이었다.
#dreamhack#ctf#pwnable+6
2026-08-02
[🥉 Bronze 3] 시드를 맞혀 37수를 미리 짜고, 이름 칸으로 셸을 부른다 — DreamHack Cat Jump 풀이
blog

[🥉 Bronze 3] 시드를 맞혀 37수를 미리 짜고, 이름 칸으로 셸을 부른다 — DreamHack Cat Jump 풀이

고양이가 37번 연속으로 장애물을 피해야 이름을 적을 수 있고, 그 이름은 snprintf 로 조립돼 system() 에 그대로 넘어간다. srand(time(NULL)) 이라 장애물 배치를 접속 시각만으로 전부 재현할 수 있어 37수를 미리 계산해 한 번에 밀어넣었고, 공백을 못 쓰는 제약은 명령 치환과 입력 리다이렉션으로 11글자에 맞춰 우회했다.
#dreamhack#ctf#pwnable+5
2026-08-02
[🥇 Gold 3] 서명 키 파일을 내가 고른다 — DreamHack KeyCat 풀이
blog

[🥇 Gold 3] 서명 키 파일을 내가 고른다 — DreamHack KeyCat 풀이

jwt.js 가 sign 과 verify 양쪽에서 keys 디렉토리 경로에 사용자 입력을 그대로 이어붙인다. 배포 zip 에 들어 있던 package.json 을 서명 키로 지정해 클레임을 위조하고, sign 이 뱉는 200과 404의 차이로 무작위 flag 파일 이름을 256번 안에 찾아냈다.
#dreamhack#ctf#web+5
2026-08-02
[🥇 Gold 4] 디버거를 붙이면 정답이 바뀐다 — DreamHack Times 풀이
blog

[🥇 Gold 4] 디버거를 붙이면 정답이 바뀐다 — DreamHack Times 풀이

생성자가 ptrace(PTRACE_TRACEME) 반환값으로 전역 워드를 갱신하는데, 그 전역이 memcmp 비교 대상의 마지막 바이트를 겸한다. MD5 XOR 층은 같은 초에 두 번 걸려 스스로 상쇄되고, 남는 변환은 dword 비트반전 하나뿐이었다.
#dreamhack#ctf#reversing+6
2026-08-02
[🥉 Bronze 2] 스택 주소를 몰라도 착지점은 안다 — DreamHack environ 풀이
blog

[🥉 Bronze 2] 스택 주소를 몰라도 착지점은 안다 — DreamHack environ 풀이

임의 주소 8바이트를 읽어 그 값으로 곧장 점프하는 원시(primitive)가 주어진다. 주소를 어디에도 쓸 수 없으니 "내가 원하는 값이 이미 들어 있는 칸"을 찾아야 하는데, libc 의 environ 이 항상 스택의 envp 배열을 가리킨다. 스택 주소를 읽지도 못한 채 거기를 착지점으로 삼고, read 오버플로우로 그 지점을 NOP 썰매로 미리 덮어 셸코드까지 미끄러뜨린다.
#dreamhack#ctf#pwnable+6
2026-08-01
[🥇 Gold 3] vtable 을 못 옮기면 libc 안의 진짜 vtable 을 빌린다 — DreamHack Bypass IO_validate_vtable 풀이
blog

[🥇 Gold 3] vtable 을 못 옮기면 libc 안의 진짜 vtable 을 빌린다 — DreamHack Bypass IO_validate_vtable 풀이

read 한 번으로 FILE 구조체 300바이트를 통째로 덮을 수 있는데, 대상이 glibc 2.27 이라 vtable 을 엉뚱한 주소로 돌리면 그 자리에서 abort 한다. 2.24 부터 fclose 안에 IO_validate_vtable 범위 검사가 인라인돼 있기 때문이다. 그래서 vtable 을 옮기는 대신 __libc_IO_vtables 섹션 안에 원래부터 있던 _IO_str_jumps 를 그대로 갖다 쓴다. 그 vtable 의 __finish 인 _IO_str_finish 는 FILE+0xe8 을 함수 포인터로 호출하는데, 그 칸도 우리가 덮는 300바이트 안에 있다.
#dreamhack#ctf#pwnable+4
2026-08-01
[🥇 Gold 4] read 한 번을 통째로 훔쳐 오는 법 — DreamHack iofile_aw 풀이
blog

[🥇 Gold 4] read 한 번을 통째로 훔쳐 오는 법 — DreamHack iofile_aw 풀이

memcpy 한 줄이 stdin 이 가리키는 FILE 구조체의 앞 0x40바이트를 통째로 갈아끼운다. 그 0x40 안에 _IO_buf_base 가 들어 있어서, 다음에 fgets 가 부르는 read(2) 의 착지점을 내가 정할 수 있다. Full RELRO 라 GOT 는 못 건드리지만 대신 전역 int 하나 — read 길이를 담고 있는 size — 를 512에서 2560으로 키웠다. 그 순간 소스에 "No overflow here" 라고 주석까지 달려 있던 read_command 가 512바이트 스택 버퍼에 568바이트를 부어 넣는 함수가 된다.
#dreamhack#ctf#pwnable+4
2026-08-01
[🥇 Gold 2] 화면에 한 자리씩 뜨는 실행파일 — DreamHack captain-hook 풀이
blog

[🥇 Gold 2] 화면에 한 자리씩 뜨는 실행파일 — DreamHack captain-hook 풀이

클릭할 때마다 16진수 한 자리를 그리는 창. 그 18,432자리를 다 모으면 UPX로 패킹된 또 하나의 실행파일이 나온다. 풀어서 실행하면 flag가 뜨는데 굵기 10.0 펜으로 그은 가림막이 글자를 덮는다. 상수 하나를 0.3으로 바꾸면 덮개가 걷힌다.
#dreamhack#ctf#reversing+5
2026-07-31
[🥈 Silver 2] stderr + 1 이 가리키는 8바이트로 함수 테이블을 갈아끼운다 — DreamHack iofile_vtable 풀이
blog

[🥈 Silver 2] stderr + 1 이 가리키는 8바이트로 함수 테이블을 갈아끼운다 — DreamHack iofile_vtable 풀이

메뉴 4번이 read(0, stderr + 1, 8) 을 한다. stderr 는 FILE 포인터라 +1 은 8바이트가 아니라 구조체 하나만큼, 즉 0xd8 을 건너뛴다. 그 자리가 하필 _IO_FILE_plus 의 vtable 포인터다. 전역 배열 name 에 get_shell 주소를 미리 넣어 두고 vtable 을 name - 0x38 로 돌리면, fwrite 가 부르는 __xsputn 칸이 정확히 name 에 겹친다.
#dreamhack#ctf#pwnable+5
2026-07-31
[🥈 Silver 4] 파일 이름을 바꾸는 기능이 Object.prototype 을 바꾼다 — DreamHack filestorage 풀이
blog

[🥈 Silver 4] 파일 이름을 바꾸는 기능이 Object.prototype 을 바꾼다 — DreamHack filestorage 풀이

파일을 올리고 읽는 Express 앱인데, 이름 변경 기능이 키를 점으로 쪼개 재귀로 대입한다. __proto__ 를 걸러내지 않아서 Object.prototype 에 값을 심을 수 있고, 파일을 읽는 쪽은 하필 그 값을 경로에 그대로 이어 붙인다. 같은 핸들러의 다른 분기는 점을 지워 버리기 때문에, 두 분기 중 어느 쪽을 타게 만드느냐가 전부였다.
#dreamhack#ctf#web+5
2026-07-31
[🥇 Gold 4] FILE 구조체를 위조해 프로그램이 제 손으로 flag를 뱉게 만들기 — DreamHack _IO_FILE Arbitrary Address Read 풀이
blog

[🥇 Gold 4] FILE 구조체를 위조해 프로그램이 제 손으로 flag를 뱉게 만들기 — DreamHack _IO_FILE Arbitrary Address Read 풀이

fopen이 돌려준 FILE 포인터가 그대로 read()의 버퍼로 넘어간다. 구조체를 통째로 위조해 fwrite가 내려가는 write(2)의 인자 셋 — fd·소스 주소·길이 — 을 전부 우리 값으로 바꾼다. _fileno=1, _IO_write_base=flag_buf로 두면 프로그램이 자기 flag를 소켓에 써 준다.
#dreamhack#ctf#pwn+5
2026-07-31
[🥉 Bronze 3] 출력이 /dev/null로 사라진다면 — DreamHack whatsdifferent 풀이
blog

[🥉 Bronze 3] 출력이 /dev/null로 사라진다면 — DreamHack whatsdifferent 풀이

명령 결과가 `> /dev/null`로 버려지고 프로그램은 뒤이어 `cat ./out`만 실행한다. 20자 제한과 16자 블랙리스트를 통과하는 `diff ff fs>out` 한 줄로 안쪽 리다이렉트를 걸어 출력을 가로채고, 두 파일 사이에서 딱 한 글자 바뀐 줄을 회수한다.
#dreamhack#ctf#misc+5
2026-07-31
[🥇 Gold 4] fread 안에 숨은 read 한 번 — DreamHack _IO_FILE Arbitrary Address Write 풀이
blog

[🥇 Gold 4] fread 안에 숨은 read 한 번 — DreamHack _IO_FILE Arbitrary Address Write 풀이

main이 fopen으로 받은 FILE 포인터를 그대로 read의 버퍼로 넘긴다. _IO_FILE 구조체를 통째로 위조할 수 있다는 뜻이다. fread는 요청량이 버퍼보다 작으면 __underflow로 내려가 read(_fileno, _IO_buf_base, 버퍼크기)를 부르는데, 이 세 인자가 전부 구조체 안에 있다. 버퍼 포인터를 전역 변수로, fd를 0으로 바꿔 stdin에서 0xDEADBEEF를 받아 적었다.
#dreamhack#ctf#pwnable+4
2026-07-30
[🥈 Silver 1] 필터가 보는 문자열과 파일시스템이 받는 문자열은 다르다 — DreamHack Dream Gallery 풀이
blog

[🥈 Silver 1] 필터가 보는 문자열과 파일시스템이 받는 문자열은 다르다 — DreamHack Dream Gallery 풀이

URL을 받아 이미지를 가져와 주는 갤러리. urlopen 앞에 필터가 세 겹 있는데, file:// 접두어 검사는 슬래시를 하나 줄이면 빗나가고 flag 문자열 검사는 퍼센트인코딩으로 빗나간다. Flask가 쿼리스트링을 한 번 풀고 url2pathname이 또 한 번 풀기 때문에, 필터가 검사하는 문자열과 open에 도달하는 경로가 애초에 같지 않다.
#dreamhack#ctf#web+6
2026-07-30
[🥉 Bronze 3] 값을 묻지 말고 지시문을 되풀이시킨다 — DreamHack baby-ai 풀이
blog

[🥉 Bronze 3] 값을 묻지 말고 지시문을 되풀이시킨다 — DreamHack baby-ai 풀이

웹 서버 안에서 0.5B 짜리 로컬 모델을 돌리는 챗봇 문제. 플래그는 시스템 프롬프트 첫 줄에 그대로 박혀 있고, 입력에 admin·flag·pass·secret·private 이 들어가면 모델까지 가지도 못한다. 그런데 그 블랙리스트는 질문만 본다. 비밀을 묻는 대신 지시문을 그대로 되풀이하게 시키면 한 줄에 다 나온다. 키릴 문자 한 글자로 부분문자열 검사 자체를 빗나가게 하는 두 번째 경로도 같이 다룬다.
#dreamhack#ctf#web+8
2026-07-29
[🥈 Silver 2] 콜론 하나로 빈 호스트를 만들어 file:// 을 통과시킨다 — DreamHack web-HTTP-CLI 풀이
blog

[🥈 Silver 2] 콜론 하나로 빈 호스트를 만들어 file:// 을 통과시킨다 — DreamHack web-HTTP-CLI 풀이

URL 을 받아 대신 긁어다 주는 43줄짜리 TCP 서비스. 호스트 화이트리스트는 눈에 잘 띄는데, 정작 대부분의 시도를 죽이는 건 그 위에 있는 튜플 언패킹이다. netloc 을 콜론으로 쪼갠 결과가 원소 2개가 아니면 검사에 닿기도 전에 ValueError 로 날아간다. netloc 을 콜론 하나로만 채우면 호스트가 빈 문자열이 되고, urllib 은 빈 호스트를 로컬로 보고 파일을 열어 준다.
#dreamhack#ctf#web+6
2026-07-29
[🥇 Gold 2] 이스케이프가 끝난 뒤에 태그를 만들면 소용이 없다 — DreamHack Guest book 풀이
blog

[🥇 Gold 2] 이스케이프가 끝난 뒤에 태그를 만들면 소용이 없다 — DreamHack Guest book 풀이

배포 파일이 함수 하나뿐인 방명록 문제. htmlentities 로 꼼꼼히 막아 놓고, 그 다음 줄에서 정규식으로 다시 a 태그를 조립한다. PHP 7.x 의 htmlentities 는 기본값이 ENT_COMPAT 라 홑따옴표를 건드리지 않고, 그 한 글자가 href 를 닫아 이벤트 핸들러를 붙일 자리를 연다. 정규식이 첫 닫는 괄호에서 끊기는 탓에 괄호 없는 JS 만 써야 한다.
#dreamhack#ctf#web+6
2026-07-29
[🥈 Silver 2] 검사기는 문자열을 보고 curl 은 URL 을 파싱한다 — DreamHack curling 풀이
blog

[🥈 Silver 2] 검사기는 문자열을 보고 curl 은 URL 을 파싱한다 — DreamHack curling 풀이

"simple api server" 라는 한 줄 설명이 전부인 문제. 46줄짜리 Flask 앱이 url 파라미터를 받아 curl 로 대신 요청해 주는데, 호스트 화이트리스트가 접두사 비교라서 URL 의 userinfo 를 끼워 넣으면 통과하고, 엔드포인트 차단은 문자열 끝만 봐서 물음표 하나에 무너진다. 두 구멍을 한 줄에 겹쳐 놓으면 서버가 자기 자신에게 요청을 보내고 플래그를 뱉는다.
#dreamhack#ctf#web+6
2026-07-29
[🥈 Silver 3] 카나리 원본이 같은 스레드 스택 안에 있다 — DreamHack Master Canary(mc_thread) 풀이
blog

[🥈 Silver 3] 카나리 원본이 같은 스레드 스택 안에 있다 — DreamHack Master Canary(mc_thread) 풀이

스레드 안에서 스택 버퍼를 위로 무제한 덮어쓸 수 있는 pwnable. 카나리를 유출할 방법이 없어 보이지만, 사실 유출할 필요가 없다. 검사에 쓰이는 원본(TLS의 fs:0x28)이 넘치는 버퍼와 같은 스레드 스택 안에 있어서, 스택 복사본과 원본을 같은 값으로 함께 덮으면 검사를 통과한다. 다만 그 사이에 놓인 TCB 필드를 그냥 뭉개면 다음 read()가 죽는다.
#dreamhack#ctf#pwnable+6
2026-07-28
[🥉 Bronze 2] GOT가 잠겨 있으면 ld.so를 본다 — DreamHack Overwrite _rtld_global 풀이
blog

[🥉 Bronze 2] GOT가 잠겨 있으면 ld.so를 본다 — DreamHack Overwrite _rtld_global 풀이

Full RELRO에 PIE까지 걸린 바이너리가 임의 주소 쓰기를 무제한으로 내준다. GOT는 읽기 전용이라 손댈 수 없지만, ld.so의 전역 구조체 _rtld_global은 RELRO 밖에 있고 프로그램이 종료될 때 _dl_fini가 그 안의 함수 포인터를 부른다. 인자와 호출 대상이 같은 구조체 안에 있어서 쓰기 두 번이면 셸이 뜬다.
#dreamhack#ctf#pwn+6
2026-07-28
[🥉 Bronze 4] 복사 금지는 브라우저에게만 하는 부탁이다 — DreamHack Ctrl-C 풀이
blog

[🥉 Bronze 4] 복사 금지는 브라우저에게만 하는 부탁이다 — DreamHack Ctrl-C 풀이

우클릭·드래그·F12를 전부 막아 둔 페이지가 2000자짜리 문자열을 보여주고 "복사할 수 있으면 해봐라"라고 한다. 그런데 그 방어는 전부 브라우저 안에서 도는 JS라, HTTP 응답 자체에는 아무 힘도 없다. curl 한 번이면 본문이 그대로 나온다. 뽑은 문자열을 배포된 스크립트에 넣으면 sha256의 base64 조각과 25바이트 상수를 XOR해 플래그가 떨어진다. 상수가 25바이트, XOR 대상이 23바이트라 출력은 입력과 무관하게 늘 두 글자가 고정된다.
#dreamhack#ctf#web+5
2026-07-28
[🥈 Silver 1] 상쇄되는 연산 14개와 미끼 키 2개 — DreamHack Ransom 풀이
blog

[🥈 Silver 1] 상쇄되는 연산 14개와 미끼 키 2개 — DreamHack Ransom 풀이

UPX 로 포장된 32비트 PE 가 flag.txt 를 두 번 암호화한다. 진짜 main 은 암호화 함수를 둘 부르는데, 하나만 보고 뒤집으면 아무것도 안 나온다. 2단계는 고정 인덱스 연산이 15개나 붙어 있지만 14개가 역연산 짝이라 상쇄되고 실질은 하나뿐이고, .rdata 의 키처럼 생긴 문자열 셋 중 둘은 스택에 복사만 되고 읽히지 않는 미끼다. 키가 파일보다 한 바이트 짧아 마지막 바이트는 초기화 안 된 스택을 읽는다.
#dreamhack#ctf#reversing+7
2026-07-28
[🥇 Gold 3] 응답을 한 글자도 못 읽는데 flag 32자가 새는 이유 — DreamHack XS-Search 풀이
blog

[🥇 Gold 3] 응답을 한 글자도 못 읽는데 flag 32자가 새는 이유 — DreamHack XS-Search 풀이

검색 결과가 매치했을 때만 iframe 이 하나 생긴다. 교차 출처라 본문·헤더·상태코드는 전부 막혀 있지만 window.length 는 늘 읽히니, 그 정수 하나로 "이 접두사가 flag 에 들어 있나"를 묻는 오라클이 된다. 봇을 33번 불러 32자리 hex 를 복원했다. 그런데 정찰 중에 제외 조건이 and 로 이어진 걸 보고 드모르간을 풀어 보니 Host 헤더만 127.0.0.1:8000 으로 바꾸면 curl 한 번으로도 끝났다. 두 경로를 다 라이브로 돌려 같은 flag 가 나오는 걸 확인했다.
#dreamhack#ctf#web+7
2026-07-28
[🥈 Silver 4] setuid 바이너리가 스스로 안전장치를 끄는 순간 — DreamHack file-special-bit 풀이
blog

[🥈 Silver 4] setuid 바이너리가 스스로 안전장치를 끄는 순간 — DreamHack file-special-bit 풀이

dream 소유의 setuid 바이너리가 argv[1] 을 그대로 "cat %s" 에 끼워 system() 으로 넘긴다. 보통은 sh 가 실행 즉시 euid 를 ruid 로 되돌려 이런 주입이 무력해지는데, 이 문제는 system() 직전에 setreuid(geteuid(), geteuid()) 로 real uid 까지 올려 버려서 sh 가 떨어뜨릴 권한을 남기지 않는다. 같은 코드에서 그 한 줄만 뺀 대조군을 만들어 차이를 직접 찍었고, filename 버퍼가 10바이트라 전체 경로가 잘리는 것도 gdb 로 확인했다.
#dreamhack#ctf#misc+7
2026-07-28
[🥉 Bronze 3] 리크도 셸도 없이 strcmp 하나를 오라클로 바꾸기 — DreamHack checkflag 풀이
blog

[🥉 Bronze 3] 리크도 셸도 없이 strcmp 하나를 오라클로 바꾸기 — DreamHack checkflag 풀이

플래그를 맞히면 Correct 를, 틀리면 Failed 를 돌려주는 것이 전부인 바이너리다. 리크할 포인터도 덮을 리턴 주소도 없다. 그런데 main 이 flag 를 담는 버퍼와 우리가 입력하는 버퍼를 같은 스택 영역에 0x40 간격으로 나란히 놓고, read 는 그보다 훨씬 긴 0xc8 바이트를 받는다. 0x40+d 바이트를 보내면 flag 앞 d 글자가 내 바이트로 덮이고, 그 상태의 strcmp 는 "flag 의 남은 뒷부분이 이거 맞아?" 라는 접미사 오라클이 된다. 뒤에서부터 한 글자씩 물어보면 16글자가 16초 만에 나온다.
#dreamhack#ctf#pwnable+7
2026-07-28
[🥇 Gold 4] RC4인 줄 알았던 암호와, 파일 하나에 숨어 있던 세 조각 — DreamHack Enc-JPG 풀이
blog

[🥇 Gold 4] RC4인 줄 알았던 암호와, 파일 하나에 숨어 있던 세 조각 — DreamHack Enc-JPG 풀이

배포물은 윈도우 실행파일 Enc 와 깨진 flag.jpg 둘뿐이다. Enc 를 뜯어보면 RC4 처럼 생긴 루틴이 나오는데 표준과 세 군데가 다르다 — 키 확장이 나머지가 아니라 AND, 키스트림이 S 박스를 한 번 더 타고, 무엇보다 0x400 청크마다 S 박스를 새로 만든다. 마지막 하나를 놓치면 JPEG 헤더만 살아나고 나머지가 전부 깨진다. 제대로 복호하면 파일 한 개 안에 JPEG 둘과 평문과 PNG 가 이어붙어 있고, 플래그는 그 셋에 나뉘어 들어 있다. 마지막 조각은 PNG 의 IDAT 길이 필드 자리에 덮여 있어서 그림으로는 영영 안 보인다.
#dreamhack#ctf#reversing+7
2026-07-27
[🥈 Silver 2] Rust 크랙미의 비트 치환을 거꾸로 돌려 64글자 입력 복원 — DreamHack CrabME 풀이
blog

[🥈 Silver 2] Rust 크랙미의 비트 치환을 거꾸로 돌려 64글자 입력 복원 — DreamHack CrabME 풀이

Rust 로 빌드된 크랙미. 입력은 64글자 소문자 hex 로 고정돼 있고, 두 글자씩 묶은 32바이트를 flagchecker 가 "비트 치환 → XOR 0x63 → +0x22" 세 단계로 바꿔 .rodata 에 박힌 상수 32개와 비교한다. 세 단계가 전부 바이트 단위 전단사라 브루트포스 없이 그대로 역산되고, 나온 64글자가 곧 플래그 본문이다. objdump 로 치환표를 유도하고 gdb 로 런타임에서 같은 값이 나오는지 확인했다.
#dreamhack#ctf#reversing+6
2026-07-26
[🥈 Silver 1] main 이라는 이름의 거짓말 — DreamHack Honest 풀이
blog

[🥈 Silver 1] main 이라는 이름의 거짓말 — DreamHack Honest 풀이

바이너리 하나만 주는 리버싱 문제. 64개 함수가 전역 counter 를 하나씩 올리며 입력을 한 글자씩 검사하는 단순한 구조인데, 그대로 역산하면 Wrong! 이 나온다. ELF 진입점을 따라가 보면 _start 가 __libc_start_main 에 넘기는 함수가 main 심볼이 아니라 verify_func_28 이다. 시작 칸이 55칸 어긋나 정답 문자열이 통째로 회전해 있었다.
#dreamhack#ctf#reversing+5
2026-07-25
[🥉 Bronze 2] 버튼 8.9억 번 대신 APK 속 SEED-128 CBC 를 직접 푼다 — DreamHack [CodeEngn] MobileApp L03 풀이
blog

[🥉 Bronze 2] 버튼 8.9억 번 대신 APK 속 SEED-128 CBC 를 직접 푼다 — DreamHack [CodeEngn] MobileApp L03 풀이

SmartApp L03.apk 는 버튼을 randomRange(44444) 번 눌러야 키값을 보여준다. 평균 8.9억 번이라 UI 로는 절대 못 본다. jadx 로 뜯어보면 그 값은 입력과 무관하게 Security.DecryptStr() 이 하드코딩 hex 를 SEED-128 CBC 로 복호한 결과였고, key 와 IV 는 dex 의 fill-array-data 페이로드에 상수로 박혀 있다. apktool 없이 classes.dex 에서 상수를 직접 긁어내 openssl seed-cbc 로 복호하면 키값 CodeEngn_4_Ever 가 나온다.
#dreamhack#ctf#reversing+9
2026-07-25
[🥈 Silver 2] 해킹당한 VM 이미지에서 채굴기가 삼킨 플래그 되찾기 — DreamHack Infested Terran 풀이
blog

[🥈 Silver 2] 해킹당한 VM 이미지에서 채굴기가 삼킨 플래그 되찾기 — DreamHack Infested Terran 풀이

bzImage + rootfs.ext2 두 파일만 주는 문제. 이미지를 마운트하지 않고 열어보면 buildroot 바이너리들 사이에 glibc로 빌드된 두 개가 섞여 있다. /home/ubuntu/.helper는 표준입력으로 받은 값을 argv[0]="[kworker]"로 위장해 /usr/bin/sl에 넘기고, sl은 입력 36글자를 힙에 흩뿌린 뒤 누적합을 하드코딩된 값과 비교한다. 검증식이 삼각행렬이라 이웃한 두 항을 빼는 것만으로 한 글자씩 그대로 복원된다.
#dreamhack#ctf#reversing+7
2026-07-25
[🥈 Silver 2] 리버싱 대신 메모리를 읽는다 — DreamHack just read memory 풀이
blog

[🥈 Silver 2] 리버싱 대신 메모리를 읽는다 — DreamHack just read memory 풀이

입력을 한 글자씩 연결리스트 노드와 비교하고, 다 맞으면 플래그를 뱉는 바이너리. 노드 값은 루프 인덱스가 아니라 세 헬퍼 함수가 공유하는 초기화 안 된 스택 슬롯과 전역 cnt 로 만든 숨은 점화식(cnt = 27*cnt + 103)에서 나온다. 그 점화식을 파이썬으로 접어 정답 입력을 복원할 수도 있지만, 문제 이름대로 gdb 로 리스트 생성 직후에 멈춰 힙을 그대로 읽어내는 게 더 빠르다.
#dreamhack#ctf#reversing+5
2026-07-24
[🥉 Bronze 2] 6523개 CAN 프레임 중 튀는 하나 — DreamHack Read My Car 풀이
blog

[🥉 Bronze 2] 6523개 CAN 프레임 중 튀는 하나 — DreamHack Read My Car 풀이

정비소에서 받아온 차량 주행 로그라며 candump 파일 하나만 준다. 열어 보면 1953가지 CAN ID가 뒤섞인 난수 덩어리인데, 등장 횟수를 세면 딱 하나만 다른 ID들보다 4배 넘게 튄다. 그 ID의 페이로드를 ASCII로 읽으면 flag가 나온다.
#dreamhack#ctf#misc+5
2026-07-24
[🥈 Silver 4] 3×10¹⁷번 세제곱을 안 기다리고 접기 — DreamHack power cube 풀이
blog

[🥈 Silver 4] 3×10¹⁷번 세제곱을 안 기다리고 접기 — DreamHack power cube 풀이

실행하면 "You've waited so long...."만 남기고 영원히 안 끝나는 바이너리 하나. 하는 일은 64비트 정수를 세제곱만 3.1×10¹⁷번 반복한 뒤 그 결과를 SHA256해서 플래그로 찍는 게 전부다. 세제곱을 쌓으면 지수가 3의 거듭제곱으로 자란다는 것과, 2⁶⁴ 곱셈군의 지수가 2⁶²라는 카마이클 정리 하나로 그 반복을 한 줄 pow로 접는다.
#dreamhack#ctf#reversing+5
2026-07-24
[🥉 Bronze 1] 바이너리가 자기 자신을 읽어 만든 열쇠 — DreamHack SelfRead 풀이
blog

[🥉 Bronze 1] 바이너리가 자기 자신을 읽어 만든 열쇠 — DreamHack SelfRead 풀이

SelfRead는 정답 문자열을 어디에도 저장해 두지 않는다. 대신 실행하면서 /proc/self/exe로 자기 ELF를 다시 읽어, 정해진 오프셋의 바이트 배치에서 열쇠를 즉석에서 만들어 낸다. 그 조립 규칙을 거꾸로 따라가면 서버 없이 파일만으로 flag를 계산할 수 있다.
#dreamhack#ctf#reversing+4
2026-07-23
[🥈 Silver 4] e 가 (p-1) 을 나누는 RSA — AMM 으로 e차근 구하기 — DreamHack special_rsa_parameter 풀이
blog

[🥈 Silver 4] e 가 (p-1) 을 나누는 RSA — AMM 으로 e차근 구하기 — DreamHack special_rsa_parameter 풀이

공개지수 e=257 이 (p-1) 을 딱 한 번 나눈다. gcd(e, φ(N)) 이 1 이 아니라 d=e⁻¹ mod φ 가 존재하지 않아 평범한 RSA 복호가 막힌다. p·q 가 이미 주어졌으니 CRT 로 mod p / mod q 로 쪼갠 뒤, e차근이 유일한 mod q 는 그대로 풀고, e차근이 257개인 mod p 는 AMM(Adleman-Manders-Miller) 으로 전부 구해 CRT 로 다시 합친다. 257개 후보 중 BISC 로 시작하는 평문이 flag.
#dreamhack#ctf#crypto+6
2026-07-23
[🥉 Bronze 3] 8827비트 RSA가 0.004초에 갈라지는 이유 — DreamHack many primes 풀이
blog

[🥉 Bronze 3] 8827비트 RSA가 0.004초에 갈라지는 이유 — DreamHack many primes 풀이

모듈러스 N 이 2658자리(8827비트)라 겁을 주지만, 실은 11부터 8293 사이의 자잘한 소수 777개를 곱해 만든 값이다. 소인수가 전부 8296 미만이라 8296까지 시행나눗셈만 돌려도 통째로 갈라진다. 서로 다른 소수의 곱이라 φ(N)=∏(pᵢ−1) 로 바로 구해지고, d=e⁻¹ mod φ 로 개인키를 복원해 복호한다.
#dreamhack#ctf#crypto+5
2026-07-23
[🥈 Silver 3] 2048비트 RSA가 0스텝에 갈라지는 이유 — DreamHack crt rsa 풀이
blog

[🥈 Silver 3] 2048비트 RSA가 0스텝에 갈라지는 이유 — DreamHack crt rsa 풀이

공개 지수 e 도 개인키 d 도 주지 않고 dp, dq, qinv 와 암호문만 주는 RSA-CRT 문제. 두 소수를 p = nextprime(q + 1) 로 만들어 사실상 연속 소수라, 2048비트 모듈러스인데도 Fermat 인수분해로 0스텝에 갈라진다. dp·dq·qinv 는 그 자체가 CRT 복호 파라미터라, 소인수만 알면 e·d 복원 없이 곧장 평문을 얻는다.
#dreamhack#ctf#crypto+4
2026-07-22
[🥉 Bronze 2] 3중으로 막아둔 안드로이드 버튼, 그래도 정적분석으로 뚫는다 — DreamHack [CodeEngn] MobileApp L02 풀이
blog

[🥉 Bronze 2] 3중으로 막아둔 안드로이드 버튼, 그래도 정적분석으로 뚫는다 — DreamHack [CodeEngn] MobileApp L02 풀이

L01과 같은 SEED-128 CBC + Java BigInteger 부호 인코딩 구조지만, 이번엔 유효 블록이 2개라 CBC 체이닝까지 풀어야 한다. onCreate()의 실행 조건은 참조비교(==)·하드코딩 상수· 불가능한 과거 시각 3중으로 막혀 있어, 앱을 실행해서는 절대 답이 안 나오게 설계됐다.
#dreamhack#ctf#reversing+6
2026-07-22
[🥉 Bronze 2] 딱 한 번의 임의 주소 쓰기로 셸 열기 — DreamHack rtld 풀이
blog

[🥉 Bronze 2] 딱 한 번의 임의 주소 쓰기로 셸 열기 — DreamHack rtld 풀이

주어진 건 `*(long*)addr = value` 딱 한 번, 그리고 stdout 리크 하나뿐이다. get_shell() 은 있지만 PIE base 를 몰라 못 쓴다. libc 훅도, FSOP 도, atexit 체인도 전부 막힌 상태에서 문제 이름이 가리키는 곳 — 로더(ld.so) 의 _rtld_global 을 노렸다. 종료 시 _dl_fini 가 호출하는 락 함수 포인터를 one_gadget 으로 덮으면 프로그램이 끝나는 순간 셸이 열린다.
#dreamhack#pwnable#rtld+3
2026-07-22
[🥉 Bronze 1] 시그널 프레임을 직접 위조해 셸을 딴다 — DreamHack SigReturn-Oriented Programming 풀이
blog

[🥉 Bronze 1] 시그널 프레임을 직접 위조해 셸을 딴다 — DreamHack SigReturn-Oriented Programming 풀이

16바이트 버퍼 오버플로우와 gadget 하나(pop rax; syscall; ret)만 있으면 커널의 rt_sigreturn을 이용해 레지스터 전체를 통째로 위조할 수 있다. 셸코드도 ROP 체인도 없이, No PIE로 고정된 BSS 주소 하나만으로 스택 리크 없이 execve("/bin/sh")까지 도달한다.
#dreamhack#ctf#pwnable+5
2026-07-22
[🥈 Silver 4] 지시문을 곧이곧대로 읽으면 끝나는 문제 — DreamHack 정ㅋ벅ㅋ 풀이
blog

[🥈 Silver 4] 지시문을 곧이곧대로 읽으면 끝나는 문제 — DreamHack 정ㅋ벅ㅋ 풀이

파일도 서버도 없이 딱 두 줄짜리 설명만 던져주는 트롤 문제. 밈 이름을 넣어보고, 백준 1237의 정답을 넣어보고 다 틀린 뒤에야, 설명 문장 자체를 글자 그대로 따르는 게 정답이라는 걸 알았다. 백준 1237 "정ㅋ벅ㅋ"의 오마주이자, 결국 답은 지시문 안에 통째로 들어 있었다.
#dreamhack#ctf#misc+2
2026-07-21
[🥉 Bronze 4] 우회할 403은 애초에 없었다 — DreamHack 403-forbbiden 풀이
blog

[🥉 Bronze 4] 우회할 403은 애초에 없었다 — DreamHack 403-forbbiden 풀이

가짜 브라우저 창 안에 "403 Forbidden"이 떠 있는 페이지. 제목부터 대놓고 "403 우회"를 암시하니 자연스럽게 X-Forwarded-For, 경로 트릭 같은 고전적인 헤더 우회 기법부터 시도하게 된다. 그런데 그 화면 속 "/secret"이라는 보호된 경로는 애초에 서버에 존재하지도 않는 눈속임이었다. view-source로 스크립트를 열어보면 진짜 취약점은 전혀 다른 곳에 있었다 — 클라이언트가 "정답 조건"을 스스로 판단해서 보내는 POST 요청을, 서버가 그 어떤 맥락도 검증하지 않고 그대로 받아준다는 사실.
#dreamhack#ctf#web+3
2026-07-21
[🥇 Gold 2] .rela.tivity — 재배치 테이블이 곧 암호문이었다, DreamHack Theori of Relativity 풀이 (2번 보류 끝에 해결)
blog

[🥇 Gold 2] .rela.tivity — 재배치 테이블이 곧 암호문이었다, DreamHack Theori of Relativity 풀이 (2번 보류 끝에 해결)

키 문자열을 입력하면 맞는지 틀렸는지만 알려주는 짧은 리버싱 문제. 검증에 쓰이는 104바이트 "키 블록"이 파일에 적힌 값과 실행 중인 값이 완전히 다른데, 그 값을 바꾸는 함수를 아무리 찾아도 안 나온다 — 지난 두 세션은 여기서 막혔다. 진짜 범인은 함수가 아니라 ".rela.tivity"라는 이름의 가짜 재배치 섹션과 그걸 진짜로 처리해버리는 ELF 로더 자신이었다. 게다가 마지막 관문에서는 "디버거로 관찰하는 행위 자체가 관찰 대상을 바꿔버리는" 진짜 물리학 농담 같은 함정까지 기다리고 있었다.
#dreamhack#ctf#reversing+5
2026-07-21
[🥈 Silver 4] 10²²년짜리 잠을 0.3초로 줄이기 — DreamHack Long Sleep 풀이 (2번 보류 끝에 해결)
blog

[🥈 Silver 4] 10²²년짜리 잠을 0.3초로 줄이기 — DreamHack Long Sleep 풀이 (2번 보류 끝에 해결)

실행하면 "flag를 생성 중"이라며 뜸을 들이다가 점점 더 길게 잠드는 바이너리. sleep()이 아니라 libc 심볼도 없는 raw syscall이라 LD_PRELOAD 후킹이 안 통하고, 파일을 패치하거나 소프트웨어 브레이크포인트를 걸면 곧바로 "integrity_check(): file has been corrupted"가 뜬다. 지난 두 세션은 이 두 방어가 서로 "같은 것"을 검사한다고 착각해 막혔다. 사실은 완전히 다른 두 층이었다 — 하나는 코드 바이트 자체의 무결성, 하나는 그저 실행 속도. 코드는 그대로 두고 syscall 인자값만 바꾸면 두 방어 다 건드리지 않고 지나간다.
#dreamhack#ctf#reversing+4
2026-07-21
[🥇 Gold 1] 27455번 반복되는 누산도 결국 선형이다 — DreamHack multipoint 풀이 (2번 보류 끝에 해결)
blog

[🥇 Gold 1] 27455번 반복되는 누산도 결국 선형이다 — DreamHack multipoint 풀이 (2번 보류 끝에 해결)

38바이트 목표값과 memcmp하는 39바이트 입력 검증기. 검증 알고리즘 자체는 단순한 곱셈-누산 루프인데, 몇 개의 레코드를 도는지가 파일 안의 데이터로 결정되는 구조라 정적으로 훑다가 "말이 안 되게 크다"는 판단을 내려 두 세션 연속 보류했던 문제다. 사실은 판단이 틀렸던 것뿐이었다 — 정말로 27455번 반복하는 게 맞았고, 그 반복이 아무리 많아도 각 항의 계수가 전부 컴파일타임 상수라는 사실을 놓치지 않으면 전체가 GF(251) 위의 선형 방정식 하나로 정리된다.
#dreamhack#ctf#reversing+4
2026-07-21
[🥉 Bronze 1] 확장자만 .md면 통과 — 내용은 아무도 안 봤다, DreamHack Pearfect Markdown 풀이
blog

[🥉 Bronze 1] 확장자만 .md면 통과 — 내용은 아무도 안 봤다, DreamHack Pearfect Markdown 풀이

실시간으로 마크다운을 미리보기 해주는 아주 단순한 PHP 페이지. 업로드 라우트는 파일 이름의 확장자가 .md인지만 검사하고, 미리보기 라우트는 그 파일을 include()로 그대로 불러온다. 두 라우트 모두 각자 보면 그럴듯한 방어처럼 보이지만, 확장자 검사는 "내용"을 전혀 보지 않고 include()는 "확장자"를 전혀 가리지 않는다는 게 문제였다. 처음엔 경로traversal로 flag 파일을 직접 읽으려 했지만 빌드 스크립트가 파일명을 32자 랜덤 문자열로 바꿔둔 탓에 실패했고, 결국 업로드한 .md 파일 안에 PHP 코드를 심어 실행시키는 쪽으로 방향을 틀었다.
#dreamhack#ctf#web+5
2026-07-21
[🥉 Bronze 3] 뚫을 필요가 없었다, 제대로 보기만 하면 됐다 — DreamHack [wargame.kr] already got 풀이
blog

[🥉 Bronze 3] 뚫을 필요가 없었다, 제대로 보기만 하면 됐다 — DreamHack [wargame.kr] already got 풀이

옛 wargame.kr에서 리마스터해 가져온 문제. 페이지를 열어보면 "you've already got key! :p"라는 한 줄짜리 문구뿐이고, HTML 소스를 봐도 똑같다. 문제 설명이 "HTTP 응답 헤더가 보이나요?"라고 대놓고 힌트를 주는데, 이 짧은 문제 하나가 사실 "브라우저 화면에 보이는 것"과 "서버가 실제로 보낸 것"이 다르다는 웹 리버싱의 가장 기초적인 교훈을 정확히 짚고 있었다. 취약점을 찾아 뚫는 문제가 아니라, HTTP 프로토콜을 있는 그대로 관찰하기만 하면 되는 문제였다.
#dreamhack#ctf#web+3
2026-07-21
[🥉 Bronze 1] "IP인지 검증했다"와 "안전하다"는 다른 말이다 — DreamHack EZ_command_injection 풀이
blog

[🥉 Bronze 1] "IP인지 검증했다"와 "안전하다"는 다른 말이다 — DreamHack EZ_command_injection 풀이

ping을 대신 실행해주는 웹 서비스. 서버는 사용자가 넣은 값을 파이썬 ipaddress.ip_address()로 "진짜 IP 주소인지" 검증한 다음에야 쉘 명령에 끼워 넣는다 — 얼핏 안전해 보이는 방어다. 그런데 IPv6 주소 뒤에 붙는 %인터페이스이름(scope id) 부분은 그 내용을 전혀 검증하지 않고 그대로 보존한다는 사실을 알게 되면서, "유효한 IP 주소"이면서 동시에 완전한 쉘 인젝션 페이로드인 문자열을 만들 수 있었다. 유일한 걸림돌은 절대경로에 들어가는 슬래시 하나 — CIDR 표기법과 헷갈려 파싱이 거부됐다.
#dreamhack#ctf#web+4
2026-07-21
[🥇 Gold 2] 코드가 스스로를 만들어낼 땐, 만드는 코드부터 읽어야 한다 — DreamHack You shall not pass 풀이
blog

[🥇 Gold 2] 코드가 스스로를 만들어낼 땐, 만드는 코드부터 읽어야 한다 — DreamHack You shall not pass 풀이

.NET/Mono 어셈블리 하나가 주어지는 리버싱 문제. ikdasm으로 Main()을 열어봐도 정작 flag를 검증하는 로직이 안 보인다 — 이 프로그램은 System.Reflection.Emit으로 검증 메서드를 실행 도중에 직접 조립해서 리플렉션으로 호출한다. "OpCode를 스택에 올리고 Emit을 부르는" 패턴이 100번 가까이 반복되는 걸 정규식 파서로 순서대로 추출해 실제 만들어질 메서드의 명령 시퀀스를 복원했다. 복원한 로직은 인접한 두 값의 순환 합을 32개의 목표값과 비교하는 방정식 시스템이었고, 이를 Z3로 직접 풀어 얻은 flag를 실제 mono 런타임에 넣어 "correct!"까지 확인했다.
#dreamhack#ctf#reversing+5
2026-07-21
[🥈 Silver 4] "L번 도니 한 번씩만 더해졌겠지"는 틀린 직관이었다 — DreamHack pybycodetes 풀이
blog

[🥈 Silver 4] "L번 도니 한 번씩만 더해졌겠지"는 틀린 직관이었다 — DreamHack pybycodetes 풀이

실행 파일이 아니라 파이썬 dis.dis() 바이트코드 덤프 두 장(main.txt, hard2rev.txt)과 출력 결과(output.txt)만 주어지는 리버싱 문제. opcode를 그대로 읽어 파이썬 소스로 재구성하면, flag를 바이트 XOR 한 뒤 값 하나에 +36을 하고 배열 전체를 j//2번 뒤집는 걸 반복하는 함수가 나온다. "루프가 L번 도니까 각 원소에 정확히 한 번씩만 더해졌겠지"라는 첫 직관은 틀렸다 — 반복되는 반전 때문에 같은 값이 여러 번 걸리기도, 아예 안 걸리기도 한다. 실제 값 대신 "위치 라벨" 배열을 똑같은 알고리즘으로 굴려 정확한 횟수와 최종 위치를 추적하고, 그 결과를 역산해 flag를 복원했다.
#dreamhack#ctf#reversing+3
2026-07-21
[🥈 Silver 4] ctype 비트 하나를 잘못 짚으면 퍼뮤테이션 전체가 어긋난다 — DreamHack Permpkin 풀이
blog

[🥈 Silver 4] ctype 비트 하나를 잘못 짚으면 퍼뮤테이션 전체가 어긋난다 — DreamHack Permpkin 풀이

chall 바이너리는 입력을 받지 않는다. 대신 미리 정해둔 sample 문자열을 스스로 뒤섞어 rev1.txt/rev2.txt로 보여줄 뿐이다. 진짜 풀어야 할 대상은 같은 방식으로 미리 변환돼 주어진 flag1.txt/flag2.txt. 바이너리 안의 23자리 hex 문자열을 ctype 기반으로 숫자 배열(퍼뮤테이션+XOR 키)로 바꾸는데, 그 변환 도중 하필 값이 0이 되는 지점이 있어서 이후 strlen()이 배열 길이를 23에서 13으로 끊어버린다. 이 함정을 처음엔 못 보고 엉뚱한 ctype 비트를 가정해 틀렸다가, gdb로 실제 프로세스의 중간 메모리 상태를 직접 찍어보고 나서야 알고리즘을 100% 검증하고 뒤집을 수 있었다.
#dreamhack#ctf#reversing+4
2026-07-21
[🥈 Silver 4] 소수 두 개가 크기부터 다르면 RSA는 절반만 뚫려도 끝난다 — DreamHack babycrypto3 풀이
blog

[🥈 Silver 4] 소수 두 개가 크기부터 다르면 RSA는 절반만 뚫려도 끝난다 — DreamHack babycrypto3 풀이

공개키(pub.pem) 하나와 암호문(ciphertext.txt) 하나가 전부인 RSA 문제. 모듈러스가 394비트밖에 안 돼서 "소수 두 개가 가까운가?"부터 의심하고 Fermat 인수분해를 시도했는데 곧바로 실패했다. 실제 결함은 전혀 달랐다 — 두 소수가 138비트와 256비트로 아예 크기 자체가 달랐다. 이렇게 극단적으로 불균형한 RSA는 작은 소수 하나만 ECM으로 뚫려도 전체가 무너진다. factordb.com에 이미 같은 모듈러스의 인수분해가 공개돼 있어 교차검증까지 마치고, 개인키를 복원해 RSA 복호 후 PKCS#1v1.5 패딩과 base64를 벗겨 flag를 얻었다.
#dreamhack#ctf#crypto+4
2026-07-21
[🥈 Silver 4] 화면에 아무것도 안 뜨는 바이너리에서 flag 뽑아내기 — DreamHack fake 풀이
blog

[🥈 Silver 4] 화면에 아무것도 안 뜨는 바이너리에서 flag 뽑아내기 — DreamHack fake 풀이

실행해도 아무것도 출력하지 않는 ELF 바이너리 하나. strace로 확인해보니 read/write 계열 syscall이 단 한 번도 없다 — 임포트된 함수조차 malloc/free뿐이다. objdump로 뜯어보니 main()은 스택에 movabs 즉시값으로 23바이트 시드 버퍼를 조립해 malloc한 뒤, reverse → 인접 바이트 교환 → XOR라는 세 단계 변환만 거쳐 곧바로 free해버린다. 화면에 찍히는 건 없지만, 그 변환 결과를 파이썬으로 그대로 재현하고 gdb로 free() 직전 힙 버퍼를 직접 들여다보는 것으로 flag를 확인했다.
#dreamhack#ctf#reversing+4
2026-07-21
[🥈 Silver 4] 프로그램이 정말로 자기 이름에게 물었다 — DreamHack What is your name? 풀이
blog

[🥈 Silver 4] 프로그램이 정말로 자기 이름에게 물었다 — DreamHack What is your name? 풀이

zip 안에 exe가 11개, 전부 파일명이 무작위 3글자로 뒤섞여 있다. 실행해도 콘솔에 아무것도 안 뜨고, sha256도 전부 다르다. cmp -l로 두 파일을 겹쳐보니 123392바이트 중 딱 2바이트만 다르다는 걸 발견하면서 실마리가 풀렸다. 각 exe는 GetModuleFileNameA로 자기 자신의 파일명을 읽어 한 글자씩 밀어서 출력할 뿐이었고, 그 결과를 순서대로 이어붙이면 그대로 flag가 된다 — "What is your name?"이 은유가 아니라, 프로그램이 진짜로 자기 자신의 이름을 묻는 질문이었다.
#dreamhack#ctf#reversing+4
2026-07-21
[🥈 Silver 2] 반복문을 없애도 제약은 사라지지 않는다 — DreamHack Call more functions 풀이
blog

[🥈 Silver 2] 반복문을 없애도 제약은 사라지지 않는다 — DreamHack Call more functions 풀이

64바이트 입력을 검증하는 함수 하나를 열어보니 반복문도, 분기문도 없다. 대신 똑같은 헬퍼 함수 네 개(push, peek, xor, compare)를 319번이나 이어서 호출하는, 완전히 펼쳐진(unrolled) 코드가 전부다. 사람 눈으로 319개의 호출을 하나하나 손으로 추적하는 대신, objdump 출력을 그대로 파싱해서 이 호출 순서를 Z3 SMT 솔버로 "재생"시켰다. 어떤 값이 정답인지 스스로 계산할 필요 없이, 검증 로직 자체를 제약 조건 덩어리로 옮겨놓기만 하면 풀린다.
#dreamhack#ctf#reversing+5
2026-07-21
[🥈 Silver 3] n도, e도, 암호문도 없이 개인키 d 하나만 준다면 — DreamHack d 풀이
blog

[🥈 Silver 3] n도, e도, 암호문도 없이 개인키 d 하나만 준다면 — DreamHack d 풀이

RSA 문제인데 공개된 값이 딱 하나, 개인키 d뿐이다. 공개키 n도, 지수 e도, 암호문도 없다. 그런데 flag 자체가 RSA의 소수 p로 그대로 쓰였다는 걸 알면 이야기가 달라진다. e·d - 1 이 (p-1)(q-1)의 배수라는 사실 하나만으로, n을 몰라도 이 숫자 하나를 완전히 소인수분해해서 p와 q를 통째로 되감을 수 있다. SageMath로 410비트 숫자를 끝까지 쪼갠 뒤, 그 조각들을 어떻게 나누면 진짜 소수 두 개가 나오는지 전수탐색으로 찾아냈다.
#dreamhack#ctf#crypto+5
2026-07-21
[🥈 Silver 4] srand() 없는 rand()는 이미 예언된 미래다 — DreamHack randzzz 풀이
blog

[🥈 Silver 4] srand() 없는 rand()는 이미 예언된 미래다 — DreamHack randzzz 풀이

"난수를 맞혀보라"는 리버싱 문제. 그런데 바이너리를 뜯어보면 어디에도 srand()가 없다 — glibc의 rand()는 시드를 명시적으로 주지 않으면 항상 똑같은 순서로 값을 뱉는 결정론적 함수이므로, 이 프로그램이 뭘 물어볼지는 실행하기도 전에 전부 계산할 수 있다. 문제는 그 다음이다. 두 번의 검증이 서로 다른 정답을 요구하는데 입력은 한 번뿐이라, 한 번의 정상 실행으로는 절대 flag 전체를 볼 수 없다. GDB로 실행 중인 프로세스의 스택 메모리를 직접 고쳐써서 두 검증을 동시에 통과시킨 끝에야 완전한 flag가 나왔다.
#dreamhack#ctf#reversing+5
2026-07-21
[🥈 Silver 3] 시리얼 검증 함수 5개는 사실 연립방정식 5개였다 — DreamHack verify 풀이
blog

[🥈 Silver 3] 시리얼 검증 함수 5개는 사실 연립방정식 5개였다 — DreamHack verify 풀이

스트립된 keygen류 리버싱 바이너리. "DH 뒤에 8자리-10자리-10자리-8자리 형식의 hex 세그먼트"를 가진 시리얼을 입력받아 형식을 검사하고, 4조각을 각각 64비트 정수로 바꾼 뒤 5개의 검증 함수를 체인으로 통과시킨다. 함수를 하나씩 디스어셈블해보면 그 5개가 전부 덧셈과 XOR로 이루어진 식이라는 게 드러난다 — a+b, b+c, c+d, a+d, b^c^d. 겉보기엔 복잡한 검증 로직이지만 결국 미지수 4개짜리 연립방정식 5개일 뿐이고, numpy로 66초 만에 유일해를 찾아낸다.
#dreamhack#ctf#reversing+5
2026-07-21
[🥈 Silver 2] MD5를 잘게 썰면 "충돌 저항성"이라는 말이 무색해진다 — DreamHack hash-browns 풀이
blog

[🥈 Silver 2] MD5를 잘게 썰면 "충돌 저항성"이라는 말이 무색해진다 — DreamHack hash-browns 풀이

스트립된 리버싱 바이너리 하나가 전부다. 입력을 받아 27바이트로 자르고, 그걸 다시 3바이트씩 9조각으로 쪼갠 뒤 각 조각의 MD5를 계산해 바이너리 안에 박혀 있는 16바이트 값과 비교한다. 27바이트 전체를 한 번에 맞히려 들면 무차별대입은 우주 나이보다 오래 걸리지만, 3바이트짜리 조각 하나의 MD5 역상은 파이썬으로 0.2초면 찾는다. 해시 함수 자체는 멀쩡한데, "작은 조각으로 쪼개 각각 검증한다"는 설계 하나가 전체 키공간을 9개의 훨씬 작은 문제로 무너뜨린다.
#dreamhack#ctf#reversing+5
2026-07-21
[🥉 Bronze 1] 가젯이 syscall 하나뿐이어도 셸은 딴다 — DreamHack send_sig SROP 풀이
blog

[🥉 Bronze 1] 가젯이 syscall 하나뿐이어도 셸은 딴다 — DreamHack send_sig SROP 풀이

NX가 켜져 있어 스택에 셸코드를 심을 수 없고, 바이너리 안에 쓸만한 ROP 가젯도 pop rax; ret 와 syscall; ret 딱 두 개뿐이다. 그런데 이 두 개만으로 충분하다 — rax에 15(rt_sigreturn)를 넣고 syscall을 호출하면 커널이 스택에서 "가짜 시그널 컨텍스트"를 읽어 모든 레지스터를 우리가 원하는 값으로 통째로 복원해준다. rax=59(execve), rdi=고정주소의 "/bin/sh"로 채운 위조 컨텍스트 하나면 별도의 리크나 다단계 체인 없이 단번에 셸이 뜬다. GDB로 그 syscall 가젯에 브레이크를 걸어 커널이 실제로 우리가 넣은 값 그대로 레지스터를 복원하는 순간을 직접 확인했다.
#dreamhack#ctf#pwnable+5
2026-07-21
[🥉 Bronze 4] 화면의 "10초 뒤 공개"는 클라이언트만의 약속이었다 — DreamHack Test Your Luck 풀이
blog

[🥉 Bronze 4] 화면의 "10초 뒤 공개"는 클라이언트만의 약속이었다 — DreamHack Test Your Luck 풀이

0부터 10000 사이의 숫자를 맞히면 flag를 준다는 게임이다. 정답은 서버 프로세스가 뜰 때 딱 한 번 뽑혀 전역변수에 박히고, 그 뒤로는 절대 바뀌지 않는다. 화면에는 "결과는 10초 뒤에 공개됩니다"라고 적혀 있지만, 그 10초는 서버가 강제하는 규칙이 아니라 브라우저 자바스크립트의 setTimeout 한 줄일 뿐이다. 직접 요청을 찔러보면 서버는 밀리초 단위로 즉시 대답한다 — 그러면 10001가지 뿐인 정답을 그냥 처음부터 끝까지 다 물어보면 된다.
#dreamhack#ctf#web+5
2026-07-21
[🥇 Gold 4] "/index.php/"조차 무해한 코드가 됐다 — DreamHack Relative Path Overwrite Advanced 풀이
blog

[🥇 Gold 4] "/index.php/"조차 무해한 코드가 됐다 — DreamHack Relative Path Overwrite Advanced 풀이

include() 대상 파일명 필터는 완벽해 보였다 — "..", ":", "/"를 전부 막으니 직접적인 LFI는 불가능하다. 그런데 그 필터는 GET 파라미터 하나만 검사할 뿐, 페이지가 상대경로로 불러오는 스크립트 파일까지는 신경 쓰지 않았다. Apache의 rewrite 규칙 하나가 확장자를 슬쩍 빠뜨리는 버그를 갖고 있었고, 그 덕에 스크립트 요청은 항상 404로 떨어져 우리가 요청한 URL을 그대로 반사하는 페이지에 도달한다. 문제는 반사된 텍스트 맨 앞에 우리가 손댈 수 없는 "/index.php/"가 항상 붙는다는 것 — 그런데 JavaScript 문법에서는 이 문자열이 우연히도 "아무 일도 하지 않는 정규식 리터럴"로 파싱된다는 걸 발견하면서 퍼즐이 풀렸다.
#dreamhack#ctf#web+5
2026-07-21
[🥉 Bronze 4] "로봇 인증"이 오히려 로봇에게 판을 깔아줬다 — DreamHack Robot Only 풀이
blog

[🥉 Bronze 4] "로봇 인증"이 오히려 로봇에게 판을 깔아줬다 — DreamHack Robot Only 풀이

숫자 하나를 3초 안에 그대로 되받아 타이핑하면 "로봇 인증"이 완료된다. 그 숫자는 Python random 모듈의 원시 출력 6개를 이어붙여 고정된 상수로 XOR한 값이라, 우리가 화면에서 읽는 순간 그 6개 숫자를 그대로 역산할 수 있다. 그리고 이 인증은 실패해도 몇 번이든 다시 시도할 수 있다 — 104번만 반복하면 Mersenne Twister의 내부 상태를 완전히 복원하는 데 필요한 624개의 연속된 원시값을 전부 모을 수 있다는 뜻이다. 그 뒤로는 서버가 뽑을 도박 게임의 정답을 베팅하기도 전에 알 수 있게 된다.
#dreamhack#ctf#misc+5
2026-07-20
[🥉 Bronze 4] mmap으로 격리한 flag도 포인터 하나면 새어나온다 — DreamHack mmapped 풀이
blog

[🥉 Bronze 4] mmap으로 격리한 flag도 포인터 하나면 새어나온다 — DreamHack mmapped 풀이

flag 파일을 mmap으로 읽기 전용 매핑해두고, 출력 직전에 mprotect로 아예 접근조차 못 하게 막아버린다 — 언뜻 보면 견고한 보호처럼 보인다. 그런데 정작 화면에 출력되는 건 "진짜 flag" 주소가 아니라 전혀 다른 곳에 있는 "가짜" 문자열의 주소다. 스택 버퍼 오버플로우로 이 두 주소가 담긴 지역 변수 두 개를 동시에 덮어쓸 수 있다면 — 보호 대상 자체를 바꿔치기해서 mprotect를 헛손질로 만들고, 출력 대상은 진짜 flag로 바꿔치는 게 가능해진다.
#dreamhack#ctf#pwnable+3
2026-07-20
[🥈 Silver 2] 검사한 곳과 실제로 간 곳이 다를 수 있다 — DreamHack crawling 풀이
blog

[🥈 Silver 2] 검사한 곳과 실제로 간 곳이 다를 수 있다 — DreamHack crawling 풀이

URL을 넣으면 그 페이지를 대신 가져와 보여주는 미니 크롤러다. 127.0.0.1 같은 내부 주소를 직접 넣으면 "전역 IP인지" 검사하는 필터가 바로 막는다. 그런데 이 필터는 딱 하나만 확인한다 — 우리가 처음 준 URL의 호스트가 가리키는 IP. requests 라이브러리는 기본적으로 HTTP 리다이렉트를 자동으로 따라간다는 사실은 전혀 고려되지 않았다. 공인 IP를 가진 내 서버가 302로 127.0.0.1의 관리자 페이지를 가리키게만 하면, 검사는 내 공인 서버를 보고 통과시키고 실제 응답은 내부 페이지에서 그대로 새어나온다.
#dreamhack#ctf#web+4
2026-07-20
[🥈 Silver 4] 키를 두 배로 늘려도 강도는 두 배가 안 된다 — DreamHack Double DES 풀이
blog

[🥈 Silver 4] 키를 두 배로 늘려도 강도는 두 배가 안 된다 — DreamHack Double DES 풀이

DES를 두 번 겹쳐 걸면 키 길이가 8바이트에서 16바이트로 늘어난다. 그런데 이 문제는 그 16바이트 중 12바이트를 고정 문자열로 미리 알려준다 — 실제로 모르는 건 단 4바이트뿐이다. 문제 제목 그대로 "4바이트 전수조사는 쉽다"지만, 두 개의 절반 키를 곱집합으로 묶어서 전수조사하면 43억 조합, 15초 제한 안에는 어림도 없다. meet-in-the-middle으로 두 키를 따로 65536가지씩만 검사하면 131072번의 DES 연산으로 끝난다 — 이 과정에서 DES가 키의 각 바이트 최하위 비트를 아예 무시한다는 사실도 우연히 다시 확인하게 됐다.
#dreamhack#ctf#crypto+3
2026-07-20
[🥉 Bronze 4] std::string 내부를 파고들다가, 정작 답은 배열 하나 옆에 있었다 — DreamHack cpp_string 풀이
blog

[🥉 Bronze 4] std::string 내부를 파고들다가, 정작 답은 배열 하나 옆에 있었다 — DreamHack cpp_string 풀이

전역 std::string에 짧은 문자열을 넣으면 Small String Optimization이 발동해 문자열 데이터가 객체 자기 자신 안에 저장된다는 사실부터 파고들었다. write_file()이 그 c_str() 포인터에서 항상 64바이트를 읽어 파일에 쓴다는 걸 보고 "짧은 문자열을 넣으면 객체 밖 메모리를 읽어 flag를 흘릴 수 있겠다"고 확신했는데, readelf로 실제 주소를 까보니 flag는 그 문자열 객체보다 앞쪽 주소에 있었다 — 읽는 방향이 반대였다. 로컬 재현도 전부 0바이트로 실패를 확인시켜줬다. 다시 보니 답은 훨씬 단순한 곳에 있었다: 인접한 두 배열과 널 종료 없는 출력.
#dreamhack#ctf#pwnable+4
2026-07-20
[🥉 Bronze 3] 이스케이프한 건 원문이었지, 해시가 아니었다 — DreamHack [wargame.kr] md5 password 풀이
blog

[🥉 Bronze 3] 이스케이프한 건 원문이었지, 해시가 아니었다 — DreamHack [wargame.kr] md5 password 풀이

mysqli_real_escape_string()이 사용자 입력을 꼼꼼히 이스케이프한다. 그런데 정작 쿼리에 들어가는 건 그 입력이 아니라 md5($ps, true) — raw 16바이트 바이너리 해시다. 해시 결과는 이스케이프 대상이 아니었다. MD5 출력은 사실상 무작위 바이트열이라, 그 바이트들이 우연히 SQL 문법으로 읽히는 문자열을 만들어낼 수 있다. 임의 문자로 시작하는 해시는 1/256 확률로 몇 초 안에 찾을 수 있지만, 실제로 익스플로잇이 되려면 5바이트가 정확히 맞아떨어져야 해서 무작위 탐색은 비현실적이다 — 대신 잘 알려진 매직 스트링을 직접 계산으로 검증하고 그대로 썼다.
#dreamhack#wargame.kr#ctf+5
2026-07-20
[🥇 Gold 4] 텍스트는 못 읽어도 속성은 읽힌다 — DreamHack CSS Injection 풀이
blog

[🥇 Gold 4] 텍스트는 못 읽어도 속성은 읽힌다 — DreamHack CSS Injection 풀이

모든 페이지의 <style> 블록에 쿼리스트링 하나가 이스케이프 없이 그대로 꽂힌다. 플래그는 관리자 메모 텍스트 안에 있는데, 처음 세운 계획 — @font-face의 unicode-range로 글자 존재 여부를 외부 요청으로 알아내고 text-indent로 위치를 잘라내는 방법 — 은 실제 브라우저로 검증해보니 완전히 틀렸다. 화면에 안 보이게 잘라낸 글자의 폰트도 브라우저는 똑같이 요청해버린다. 결국 플래그 텍스트가 아니라 마이페이지의 API 토큰이 <input value="..."> 속성으로 노출된다는 걸 발견하고서야 고전적인 속성 선택자 유출로 방향을 틀었다. 관리자 봇을 8번만 왕복시켜 8자리 토큰을 통째로 복원했다.
#dreamhack#ctf#web+4
2026-07-20
[🌱 Sprout] 문제 만든 사람이 엔디언을 깜빡했다 — DreamHack littlevsbig 풀이
blog

[🌱 Sprout] 문제 만든 사람이 엔디언을 깜빡했다 — DreamHack littlevsbig 풀이

소스에는 int_arr[0] == 0x64726d68, int_arr[1] == 0x636b3a29라는 비교식이 그대로 노출돼 있다. 16진수를 사람 눈으로 그대로 읽으면 "drmhck:)" — "dreamhack :)"을 줄인 문자열처럼 보인다. 그런데 그 문자열을 그대로 입력하면 프로그램은 거부한다. x86은 little-endian이라 4바이트 정수를 메모리에 거꾸로 저장하기 때문에, 실제로 입력해야 하는 바이트열은 각 4바이트 워드 단위로 뒤집힌 "hmrd):kc"다. GDB로 스택 위 바이트를 직접 찍어 그 반전을 눈으로 확인했다.
#dreamhack#ctf#misc+3
2026-07-20
[🥈 Silver 3] Full RELRO·카나리·CET가 다 켜져 있어도 상관없었다 — DreamHack pwn-library 풀이
blog

[🥈 Silver 3] Full RELRO·카나리·CET가 다 켜져 있어도 상관없었다 — DreamHack pwn-library 풀이

checksec을 돌리면 RELRO, 카나리, NX, PIE에 SHSTK·IBT(Intel CET)까지 전부 켜져 있다. ROP도, 카나리 우회도, 컨트롤플로우 하이재킹도 전부 무의미한 방어벽이다. 그런데 취약점은 그 어느 것과도 상관없는 곳에 있었다 — 책을 반납하는 함수가 배열 인덱스를 줄이지 않고 포인터도 지우지 않은 채로 free()만 호출한다. 이 댕글링 포인터를 독립된 malloc 호출 하나가 tcache에서 그대로 주워가면서, "이미 반납한 책"과 "방금 훔친 새 책"이 메모리 상에서 완전히 같은 주소를 가리키게 된다. 리크도, ROP도 없이 순수한 포인터 앨리어싱만으로 로컬 파일을 통째로 읽어냈다.
#dreamhack#ctf#pwnable+4
2026-07-20
[🥈 Silver 2] 연결은 미리 다 맺어두고 마지막 1바이트만 아꼈다 — DreamHack chocoshop 레이스 컨디션 풀이
blog

[🥈 Silver 2] 연결은 미리 다 맺어두고 마지막 1바이트만 아꼈다 — DreamHack chocoshop 레이스 컨디션 풀이

쿠폰 하나로 1000원, 플래그는 2000원. 세션당 쿠폰은 딱 한 번만 발급된다는 제약이 있었지만, "이미 받았는지 확인"과 "받았다고 기록"하는 두 Redis 명령 사이에는 짧은 틈이 있었다. requests + ThreadPoolExecutor로 30개를 동시에 쏴봤지만 결과는 1장뿐이었다 — 스레드마다 새로 여는 connect() 오버헤드가 도착 시각을 흩어놓은 탓이었다. 소켓을 전부 미리 열어두고, 헤더의 마지막 1바이트만 아껴뒀다가 한 번에 흘려보내는 single-packet 기법까지 가서야 100건 중 90건 넘는 쿠폰을 한 번에 받아냈다.
#dreamhack#ctf#web+5
2026-07-20
[🥈 Silver 4] 서버가 아니라 내 코드가 죽어있었다 — DreamHack __environ 풀이
blog

[🥈 Silver 4] 서버가 아니라 내 코드가 죽어있었다 — DreamHack __environ 풀이

Full RELRO·PIE·스택 카나리가 전부 켜진 바이너리에 주어진 건 임의 주소를 문자열로 읽어주는 오라클 하나뿐이다. libc 주소를 새고, 그 안의 environ 심볼을 다시 같은 오라클로 읽어 스택 주소까지 얻어내는 원리 자체는 금방 세웠다. 그런데 익스플로잇을 돌리면 두 번째 leak마다 서버가 죽은 것처럼 연결이 끊겼다 — 범인은 서버가 아니라 내가 짠 파이썬 코드의 프로토콜 상태 관리였다.
#dreamhack#ctf#pwnable+4
2026-07-20
[🥈 Silver 3] 값을 바꾸면 검사를 피해간다 — DreamHack Textbook-RSA 풀이
blog

[🥈 Silver 3] 값을 바꾸면 검사를 피해간다 — DreamHack Textbook-RSA 풀이

암호화된 플래그를 그대로 서버에 되돌려 복호화를 요청하는 뻔한 시도는 "Do not cheat !"로 바로 막힌다. 하지만 그 검사는 딱 숫자 하나만 비교할 뿐이다. RSA는 곱셈에 대해 준동형(homomorphic)이라는 성질이 있어서, 암호문에 알려진 값을 곱해 완전히 다른 숫자로 둔갑시키면 검사를 통과하면서도 원래 값을 복원할 수 있는 정보를 그대로 얻어낼 수 있다.
#dreamhack#ctf#crypto+3
2026-07-20
[🥉 Bronze 4] 버튼을 쫓아갈 필요가 없었다 — DreamHack Click me! 풀이
blog

[🥉 Bronze 4] 버튼을 쫓아갈 필요가 없었다 — DreamHack Click me! 풀이

마우스가 가까이 가면 도망가는 버튼. "Catch me if you can!"이라는 문제 설명 그대로, 겉보기엔 반응속도와 클릭 타이밍을 겨루는 미니게임 같다. 그런데 버튼의 클릭 이벤트가 하는 일이라곤 특정 URL로 이동하는 것뿐이고, 그 URL에 서버가 어떤 조건도 검증하지 않는다는 걸 소스에서 확인한 순간, 버튼을 쫓아다닐 이유 자체가 사라졌다.
#dreamhack#ctf#web+2
2026-07-20
[🥈 Silver 2] 모든 스레드가 같은 카나리를 쓴다 — DreamHack master_canary 풀이
blog

[🥈 Silver 2] 모든 스레드가 같은 카나리를 쓴다 — DreamHack master_canary 풀이

스레드를 만들고 그 스택 버퍼에 무제한으로 읽고 쓸 수 있는 pwnable. 스레드는 함수가 끝나자마자 죽어버리는데, 전역 포인터는 계속 그 죽은 스택을 가리킨다. 죽은 스택을 따라 계속 걸어 올라가면 그 스레드의 TCB, 그리고 그 안의 canary(스택 카나리)에 닿는다 — 이 canary는 프로세스를 만들 때 단 한 번 생성돼 모든 스레드가 그대로 나눠 쓰는 "마스터" 카나리였다.
#dreamhack#ctf#pwnable+4
2026-07-20
[🥈 Silver 3] 20,664줄 로그 속의 침입 — DreamHack weblog-1 풀이
blog

[🥈 Silver 3] 20,664줄 로그 속의 침입 — DreamHack weblog-1 풀이

실행 중인 서버를 직접 공격하는 문제가 아니다. 이미 침해당한 게시판의 Apache 접속 로그 2만 줄과 소스 코드가 통째로 주어지고, 라이브 퀴즈 앱이 그 침해 과정을 단계별로 캐묻는다. blind SQLi로 로그를 파싱해 탈취된 자격증명을 재구성하고, 세션 파일 include로 이어진 RCE, 그리고 날짜를 키로 스스로를 복호화하는 웹쉘 드로퍼까지 — 로그 자체가 유일한 증거이자 유일한 공격 도구였다.
#dreamhack#ctf#web+4
2026-07-20
[🥇 Gold 4] 범인은 서버가 아니라 curl이었다 — DreamHack Flask-Dev 풀이
blog

[🥇 Gold 4] 범인은 서버가 아니라 curl이었다 — DreamHack Flask-Dev 풀이

16줄짜리 Flask 앱. 임의 파일을 읽어주는 라우트가 있고, debug=True로 Werkzeug 인터랙티브 콘솔까지 열려 있다. 그런데 정작 "../"로 상위 디렉터리를 탈출하려 하면 매번 서버가 파일명을 그대로 못 찾는다. 범인은 서버의 방어 로직이 아니라, 요청을 보내는 curl 자신이 URL을 미리 손질해 보내고 있었다는 사실이었다.
#dreamhack#ctf#web+4
2026-07-20
[🥈 Silver 2] 4개만 막고 나머진 다 열어뒀다 — DreamHack Bypass SECCOMP-1 풀이
blog

[🥈 Silver 2] 4개만 막고 나머진 다 열어뒀다 — DreamHack Bypass SECCOMP-1 풀이

임의 셸코드를 그대로 실행시켜주는 pwnable인데, execve로 셸을 따는 흔한 루트가 seccomp로 막혀 있다. 그런데 이 필터는 시스템콜 "번호" 네 개만 콕 집어 차단하는 화이트리스트가 아니라 블랙리스트였다. 목록에 없는 시스템콜은 전부 통과한다는 뜻이라, open 대신 openat으로 파일을 열고 write 대신 sendfile로 그 내용을 그대로 흘려보냈다.
#dreamhack#ctf#pwnable+3
2026-07-20
[🥉 Bronze 3] 크기 변수 자체가 과일이었다 — DreamHack Cherry 풀이
blog

[🥉 Bronze 3] 크기 변수 자체가 과일이었다 — DreamHack Cherry 풀이

read()를 두 번 부르는 아주 짧은 pwnable. 첫 read는 6바이트짜리 버퍼에 16바이트를 받아 명백히 넘치는데, 그 넘친 자리에 하필 두 번째 read가 쓸 크기(buf_size)를 결정하는 변수 자체가 놓여 있었다. 첫 오버플로우로 크기 제한 자체를 풀어버리면, 두 번째 오버플로우는 원하는 만큼 얼마든지 써도 되는 오버플로우가 된다.
#dreamhack#ctf#pwnable+3
2026-07-20
[🥉 Bronze 2] true는 모든 문자열과 같다 — DreamHack [wargame.kr] type confusion 풀이
blog

[🥉 Bronze 2] true는 모든 문자열과 같다 — DreamHack [wargame.kr] type confusion 풀이

"Simple Compare Challenge. hint? you can see the title of this challenge. :D" 소스도 없이 딱 이 한 줄이 힌트로 주어진다. view-source로 드러난 PHP 코드는 서버만 아는 랜덤 문자열과 사용자 입력을 == 로 비교하는 게 전부다. 값을 맞히는 문제가 아니라, PHP가 서로 다른 타입을 비교할 때 값 대신 타입으로 승부가 갈린다는 사실을 이용하는 문제였다.
#dreamhack#ctf#web+3
2026-07-20
[🥈 Silver 1] 필터를 뚫지 않고 굶겨 죽였다 — DreamHack Relative Path Overwrite 풀이
blog

[🥈 Silver 1] 필터를 뚫지 않고 굶겨 죽였다 — DreamHack Relative Path Overwrite 풀이

XSS 필터가 걸린 페이지를 만나면 반사적으로 필터를 통과하는 페이로드부터 찾게 된다. 이 문제는 그 방향이 아니었다 — 필터 자체를 구현한 스크립트 파일을 아예 로드되지 못하게 만들면, 필터 로직은 실행조차 되지 않는다. PHP의 상대경로 include와 브라우저의 상대경로 script src가 서로 다른 기준점을 가진다는 점을 이용해, 필터 스크립트를 페이지 자기 자신으로 뒤바꿔치기했다.
#dreamhack#ctf#web+3
2026-07-20
[🥉 Bronze 1] 정답은 예시 안에 있었다 — DreamHack [CodeEngn] Malware L01 풀이
blog

[🥉 Bronze 1] 정답은 예시 안에 있었다 — DreamHack [CodeEngn] Malware L01 풀이

악성코드 소스 코드 조각 하나만 던져주고 "이것의 공격방법은 무엇인가"를 묻는 문제. 코드를 뜯어보면 SYN 플래그를 고정하고 출발지 IP를 매 패킷 랜덤으로 바꾸며 ACK 없이 영원히 쏘는, 교과서적인 SYN Flood다. 더 정확한 용어로 답을 냈다가 두 번 오답을 먹고 나서야, 문제가 준 예시 문구 자체가 정답이었다는 걸 깨달았다.
#dreamhack#ctf#misc+3
2026-07-20
[🥉 Bronze 1] 두 번의 XOR은 상쇄되지 않았다 — DreamHack ez_rev 풀이
blog

[🥉 Bronze 1] 두 번의 XOR은 상쇄되지 않았다 — DreamHack ez_rev 풀이

"함수가 너무 많아요"라는 문제 설명과 달리 실제로 입력을 건드리는 함수는 셋뿐이다. 회전 두 번과 XOR 두 번이 교차로 걸려 있는데, 같은 키로 XOR을 두 번 하니 그냥 상쇄될 거라 생각하고 지름길을 탔다가 완전히 다른 문자열이 나왔다. 원인은 두 XOR 사이에 낀 회전 하나가 인덱스 정렬 자체를 바꿔버린다는 점이었다.
#dreamhack#ctf#reversing+2
2026-07-20
[🥉 Bronze 1] 키는 GOT 뒤에 숨어 있었다 — DreamHack basic_CrackMe 풀이
blog

[🥉 Bronze 1] 키는 GOT 뒤에 숨어 있었다 — DreamHack basic_CrackMe 풀이

32비트 PIE ELF와 Windows PE가 세트로 나오는 리버싱 문제. 겉보기엔 흔한 XOR 크랙미인데 막상 열어보면 XOR 한 번이 아니라 자릿수마다 제곱·뺄셈·덧셈이 섞인 int64 배열 연산이라 손으로 따라가면 금방 헷갈린다. 진짜 함정은 알고리즘이 아니라 키 위치 — 키 문자열은 코드 어디에도 안 보이고 GOT 슬롯에 꽂힌 포인터 하나가 .rodata를 가리키고 있었다.
#dreamhack#ctf#reversing+3
2026-07-20
[🥉 Bronze 1] LSB엔 없다, 주파수에 있다 — DreamHack Audio Steganography 풀이
blog

[🥉 Bronze 1] LSB엔 없다, 주파수에 있다 — DreamHack Audio Steganography 풀이

6초짜리 WAV 파일 하나가 전부인 포렌식 문제. 오디오 스테가노그래피라고 하면 반사적으로 LSB(최하위 비트)부터 뽑아보게 되는데, 그렇게 나온 결과는 그냥 잡음이다. "이상한 소리가 나요"라는 문제 설명을 다시 읽고 스펙트로그램을 찍어보면, 주파수 영역에 flag 문자열이 글자 모양 그대로 그려져 있다. 데이터를 비트에 숨긴 게 아니라 진폭을 붓 삼아 그림을 그린, Aphex Twin류 스펙트로그램 아트다.
#dreamhack#ctf#forensics+4
2026-07-20
[🥉 Bronze 2] .img라 쓰고 gzip이라 읽는다 — DreamHack smart_device 풀이
blog

[🥉 Bronze 2] .img라 쓰고 gzip이라 읽는다 — DreamHack smart_device 풀이

IoT 기기의 펌웨어 파일 하나만 던져주고 "API 키를 뽑아내라"는 문제. 확장자는 .img지만 첫 세 바이트(1f 8b 08)를 보면 실제로는 gzip이다. binwalk를 돌려보려 했더니 환경의 capstone 버전 충돌로 죽어버려서, gunzip과 tar로 같은 과정을 수동으로 재현했다. 풀린 tar 안 임베디드 루트 파일시스템의 설정 파일에 API 키가 평문으로 그대로 박혀 있었다.
#dreamhack#ctf#misc+3
2026-07-20
[🥉 Bronze 1] 위성이 보낸 오디오 속 flag를 힐베르트 변환으로 복조한다 — DreamHack 산타 할아버지도 힘들어요 풀이
blog

[🥉 Bronze 1] 위성이 보낸 오디오 속 flag를 힐베르트 변환으로 복조한다 — DreamHack 산타 할아버지도 힘들어요 풀이

제공되는 건 이상한 8비트 WAV 파일 두 개뿐이다. 스펙트로그램을 찍어봐도 단조로운 톤 하나만 보일 뿐 아무 정보도 없어 보인다. 문제 설명 속 "NOAA 15"라는 이름이 결정적인 힌트였다 — 기상위성이 실시간으로 지구 사진을 내려보내는 아날로그 방송 규격 APT(Automatic Picture Transmission)의 오디오였다. 2400Hz 서브캐리어를 힐베르트 변환으로 AM 복조하고 4160word/line 픽셀 클럭에 맞춰 리샘플링하면, 한반도와 일본 해안선이 그대로 찍힌 위성사진 위에 flag가 그려져 있다.
#dreamhack#ctf#misc+5
2026-07-20
[🥉 Bronze 1] 위치 무관 바이트 변환은 256개짜리 표 하나로 뒤집힌다 — DreamHack ezmix 풀이
blog

[🥉 Bronze 1] 위치 무관 바이트 변환은 256개짜리 표 하나로 뒤집힌다 — DreamHack ezmix 풀이

stripped 바이너리가 program.bin이라는 2바이트짜리 opcode 프로그램을 해석해 우리가 입력한 문자열을 ADD/XOR/ROR 256번 연속으로 뒤섞는다. 언뜻 복잡해 보이지만 세 연산 전부 버퍼의 모든 바이트에 같은 인자를 똑같이 적용할 뿐이라, 입력 위치와 무관하게 0~255 전체에 대해 한 번만 정방향 표를 만들면 역표는 자동으로 나온다. output.bin 36바이트에 역표를 그대로 대입해 flag를 즉시 복원했다.
#dreamhack#ctf#reversing+3
2026-07-20
[🥉 Bronze 4] 80바이트 버퍼에 128바이트를 채워 tmp_fd를 훔친다 — DreamHack awesome-basics 풀이
blog

[🥉 Bronze 4] 80바이트 버퍼에 128바이트를 채워 tmp_fd를 훔친다 — DreamHack awesome-basics 풀이

chall.c 는 flag 를 읽어 지역변수 tmp_fd 가 가리키는 파일에 쓰기만 할 뿐, 그 결과를 우리에게 보여주는 코드가 없다. 그런데 바로 위에서 read(stdin, buf, 0x80) 이 buf[80] 보다 48바이트 더 받는다. 이 여유분으로 buf 바로 뒤에 붙어 있는 tmp_fd 를 표준출력(1)으로 덮으면, 뒤이은 write(tmp_fd, flag, 0x45) 가 그대로 우리 화면에 flag 를 찍어준다.
#dreamhack#ctf#pwn+4
2026-07-20
[🥉 Bronze 1] PHP7 타입 저글링 두 방으로 관리자 로그인 — DreamHack easy-login 풀이
blog

[🥉 Bronze 1] PHP7 타입 저글링 두 방으로 관리자 로그인 — DreamHack easy-login 풀이

관리자 비밀번호와 OTP는 매 요청 서버에서 무작위로 재생성돼 브루트포스가 불가능하다. 대신 검증 로직 두 곳이 PHP7 특유의 느슨한 타입 비교에 기대고 있다. otp에 정수 0을 넣으면 "P123456" 같은 비숫자 문자열과 0이 같다고 판정되고, pw에 빈 배열을 넣으면 strcmp()가 타입 에러로 NULL을 반환해 통과된다. login.php를 거치지 않고 index.php에 직접 JSON을 POST해 타입을 완전히 통제했다.
#dreamhack#ctf#web+3
2026-07-20
[🥉 Bronze 1] 64바이트를 6개 함수가 나눠 검증하는 crackme — DreamHack mix-compare 풀이
blog

[🥉 Bronze 1] 64바이트를 6개 함수가 나눠 검증하는 crackme — DreamHack mix-compare 풀이

64바이트 입력을 check → check_not → check_add → check_dec → check_mul → check_la 여섯 함수가 10바이트 안팎씩 나눠 맡아 각자 다른 산술 변환(NOT·덧셈·뺄셈·곱셈·역방향 덧셈)으로 검증한다. 비교 대상 배열은 .data에 평문 정수로 그대로 박혀 있어서, 각 구간의 변환을 거꾸로 풀기만 하면 64바이트 전체가 그대로 복원된다.
#dreamhack#ctf#reversing+3
2026-07-20
[🥈 Silver 3] BPF 필터가 조용히 실패하면 seccomp는 그냥 없는 셈이다 — DreamHack seccomp 풀이
blog

[🥈 Silver 3] BPF 필터가 조용히 실패하면 seccomp는 그냥 없는 셈이다 — DreamHack seccomp 풀이

scanf("%ld", addr)가 &value 대신 addr 자체를 받는 write-what-where로 전역 seccomp 모드를 STRICT에서 FILTER로 바꿔치기한다. 컴파일된 BPF 필터 배열은 마지막 명령이 BPF_RET이 아니라서 커널 검증에서 -EINVAL로 튕기는데, 그 실패를 코드가 확인하지 않아 seccomp가 통째로 무효화된다.
#dreamhack#ctf#pwnable+4
2026-07-20
[🥉 Bronze 1] 홈브루 RSA, 모듈러스가 32비트면 그냥 나눠본다 — DreamHack public 풀이
blog

[🥉 Bronze 1] 홈브루 RSA, 모듈러스가 32비트면 그냥 나눠본다 — DreamHack public 풀이

키 생성 시드도, p·q도 안 주고 공개 모듈러스 n1과 공개지수 n2만 준다. 그런데 그 n1이 32비트급(약 42억)이라 시험 나눗셈만으로 즉시 소인수분해된다. objdump로 뜯은 키생성 로직과 gdb 런타임 검증으로 알고리즘을 확정하고 개인키를 복원해 플래그를 복호했다.
#dreamhack#ctf#reversing+5
2026-07-19
[🥈 Bronze 2] 함수 주소일까, 호출 지점일까 — DreamHack [CodeEngn] Malware L08 풀이
blog

[🥈 Bronze 2] 함수 주소일까, 호출 지점일까 — DreamHack [CodeEngn] Malware L08 풀이

다른 악성코드를 실행해 추가 감염을 일으키는 함수의 주소를 찾으라는 문제. 그래프 전체가 ShellExecuteExA로 대상 파일을 실행하는 하나의 함수인데, 그 함수 자체의 시작 주소를 냈다가 오답을 받았다. 함수 안에 ShellExecuteExA 호출이 두 곳이라는 걸 알고도 어느 쪽인지 헷갈렸는데, 결국 "함수의 주소"가 가리키는 건 실행 API를 호출하는 그 지점이었다.
#dreamhack#ctf#reversing+5
2026-07-19
[🥈 Bronze 2] 미끼인 줄 알았던 디코드가 사실 정답이었다 — DreamHack 아 문제 이름 뭘로하지 풀이
blog

[🥈 Bronze 2] 미끼인 줄 알았던 디코드가 사실 정답이었다 — DreamHack 아 문제 이름 뭘로하지 풀이

39바이트 암호문을 XOR 0xAA로 풀면 그럴듯한 DH{} 문자열이 바로 나온다. 너무 쉬워서 미끼라고 판단하고, 사용자 입력을 변형하는 복잡한 커스텀 인코딩 함수를 통째로 역산했다. GDB로 대조하다 32비트 시프트 카운트 마스킹 때문에 특정 자리가 항상 0이 되는 버그를 발견했고, 그 버그를 쫓아가다 결국 처음 봤던 그 디코드 문자열이 진짜 정답이었다는 걸 알게 됐다.
#dreamhack#ctf#reversing+4
2026-07-19
[🥉 Bronze 4] strncmp(18) 부분비교 + 시간기반 토큰 — DreamHack angry_darim 풀이
blog

[🥉 Bronze 4] strncmp(18) 부분비교 + 시간기반 토큰 — DreamHack angry_darim 풀이

time()으로 매초 바뀌는 "동적 토큰"을 strncmp로 딱 18바이트만 비교하는 바이너리. 로컬에서는 실행 순간의 epoch를 그대로 넣어 우회하지만, 정작 DreamHack에 내는 flag는 그 시간 요소를 통째로 들어내야 하는 정적 문자열이었다.
#dreamhack#ctf#pwnable+5
2026-07-19
[🥈 Bronze 2] 난독화된 전역 변수를 GDB로 그대로 읽어내기 — DreamHack Stop before stops! 풀이
blog

[🥈 Bronze 2] 난독화된 전역 변수를 GDB로 그대로 읽어내기 — DreamHack Stop before stops! 풀이

C++ 바이너리인데 함수·전역변수 이름이 전부 무작위 문자열로 바뀌어 있다. 정적 분석으로 로직은 다 읽히는데(24자 비밀번호를 비교해 맞으면 flag를 출력), 실제 비교 대상 문자열은 실행 시점에 조용히 채워지는 전역 std::string이라 정적 디스어셈블리만으론 값을 알 수 없다. GDB로 static initializer가 끝난 직후 raw 메모리를 읽어 값을 그대로 꺼냈다.
#dreamhack#ctf#reversing+5
2026-07-19
[🥉 Bronze 3] 뮤텍스가 두 개인 악성코드에서 Thread Mutex 골라내기 — DreamHack [CodeEngn] Malware L06 풀이
blog

[🥉 Bronze 3] 뮤텍스가 두 개인 악성코드에서 Thread Mutex 골라내기 — DreamHack [CodeEngn] Malware L06 풀이

같은 악성코드(bagla downloader) 그래프를 다루는 CodeEngn 시리즈의 또 다른 문제. 이번엔 뮤텍스가 두 개 나온다 — 프로그램 시작 시 만드는 프로세스 단일실행 가드용, 그리고 CreateThread 직후 만드는 두 번째 뮤텍스. 문제가 묻는 "Thread Mutex"는 스레드 생성과 바로 붙어 있는 후자다.
#dreamhack#ctf#reversing+5
2026-07-19
[🥉 Bronze 4] 똑같아 보이는 이미지 100장 속 진짜 하나 — DreamHack Find Real One 풀이
blog

[🥉 Bronze 4] 똑같아 보이는 이미지 100장 속 진짜 하나 — DreamHack Find Real One 풀이

문제 설명이 화면에 똑같이 생긴 썸네일 100개로 도배돼 있다. 파일도 서버도 없고, 눈으로는 100개가 전부 같아 보인다. 각 이미지의 클릭 대상(href)을 다수결로 비교하면 99개는 "This is fine" 밈으로, 1개만 실제 flag 이미지로 연결된다는 걸 알 수 있다.
#dreamhack#ctf#web+3
2026-07-19
[🥉 Bronze 1] 스트립된 PIE 바이너리의 커스텀 RLE 역산 — DreamHack secret message 풀이
blog

[🥉 Bronze 1] 스트립된 PIE 바이너리의 커스텀 RLE 역산 — DreamHack secret message 풀이

드림이가 이미지를 자기가 만든 인코딩으로 압축해뒀다. 스트립된 PIE ELF를 objdump로 뜯어 fopen/fgetc/fputc 호출만으로 커스텀 RLE 상태머신을 복원하고, gdb 런타임 검증까지 거쳐 원본 비트맵을 되살린 풀이.
#dreamhack#ctf#reversing+3
2026-07-19
[🥉 Bronze 4] 가짜 함수 199개 속에서 flag 찾기 — DreamHack please, please, please 풀이
blog

[🥉 Bronze 4] 가짜 함수 199개 속에서 flag 찾기 — DreamHack please, please, please 풀이

stripped PIE 바이너리 안에 거의 동일한 함수가 199개 박혀 있다. 전부 "please~"만 출력하는 죽은 코드고, 실제 main도 puts 한 줄만 부르고 끝난다. objdump로 199개 중 유일하게 다른 함수를 찾아내면 "Hhu,"라는 또 다른 미끼가 나오는데, 정작 flag는 strings 한 번이면 바로 보이는 DH{NOGADA}였다.
#dreamhack#ctf#reversing+5
2026-07-19
[🥉 Bronze 4] IDA 그래프 한 장으로 끝내는 악성코드 재접속 주기 — DreamHack [CodeEngn] Malware L07 풀이
blog

[🥉 Bronze 4] IDA 그래프 한 장으로 끝내는 악성코드 재접속 주기 — DreamHack [CodeEngn] Malware L07 풀이

실행 파일 대신 IDA 그래프 캡쳐 한 장(07.pdf)만 주어진다. 악성코드가 C2 서버 접속에 실패했을 때 몇 ms 간격으로 재시도하는지를 묻는데, 그래프 안의 재시도 루프를 따라가면 `push 96000h` → `call ds:Sleep`가 답이다. 16진수 0x96000을 10진수로 환산한 614400이 flag가 된다.
#dreamhack#ctf#reversing+5
2026-07-19
[🥉 Bronze 4] 심볼 없는 STM32F4 펌웨어에서 진짜 키 찾기 — DreamHack Please Discover my Discovery key 풀이
blog

[🥉 Bronze 4] 심볼 없는 STM32F4 펌웨어에서 진짜 키 찾기 — DreamHack Please Discover my Discovery key 풀이

769바이트짜리 stripped Cortex-M 펌웨어 하나가 전부다. strings 를 걸면 "진짜 키"를 묻는 미끼 문자열들이 우수수 나오는데, 정작 보드가 UART 로 뱉는 값은 판독 불가능한 바이트다. Thumb 코드를 디스어셈블하고 Unicorn 으로 돌려보면 그 바이트가 두 base64 문자열의 XOR 임이 드러나고, 되돌리면 숨은 메시지가 나온다.
#dreamhack#ctf#misc+6
2026-07-17
[🥉 Bronze 2] IV를 파일명에 흩뿌린 AES-CBC — DreamHack 씨뿌리기 풀이
blog

[🥉 Bronze 2] IV를 파일명에 흩뿌린 AES-CBC — DreamHack 씨뿌리기 풀이

AES-128-CBC의 ciphertext와 key만 주고 IV는 안 준다. 대신 씨앗·곡물 사진 6장을 hint로 던진다. 사진 속을 아무리 뒤져도 안 나오는데, IV는 여섯 파일'명'에 hex 조각으로 잘려 있었다. 번호순으로 이어 붙여 복호하면 flag가 나오는 crypto+forensics 문제다.
#dreamhack#ctf#crypto+4
2026-07-16
[🥉 Bronze 3] stripped Rust 바이너리에서 스택 key 를 뽑아 XOR 역산 — DreamHack Rusty Gyul 풀이
blog

[🥉 Bronze 3] stripped Rust 바이너리에서 스택 key 를 뽑아 XOR 역산 — DreamHack Rusty Gyul 풀이

심볼을 모두 걷어낸 Rust ELF 하나가 "플래그를 맞춰봐"라고 한다. ltrace 에는 strcmp 하나 안 잡히고 main 은 껍데기뿐이다. 진짜 검사 루틴을 어셈블리에서 찾아 들어가 보면, 입력을 trim 한 뒤 스택에 실어둔 32바이트 key 와 한 바이트씩 XOR 해서 전부 0x55 인지만 본다. key 를 그대로 뽑아 0x55 로 되XOR 하면 플래그가 나온다.
#dreamhack#ctf#reversing+5
2026-07-16
[🥉 Bronze 3] 안드로이드 APK 속 SEED-128 CBC 키값 복원 — DreamHack [CodeEngn] MobileApp L01 풀이
blog

[🥉 Bronze 3] 안드로이드 APK 속 SEED-128 CBC 키값 복원 — DreamHack [CodeEngn] MobileApp L01 풀이

SmartApp L01.apk 를 jadx 로 뜯어보니 버튼을 누르면 Security.DecryptStr() 가 하드코딩된 hex 문자열을 SEED-128 CBC 로 복호해 "Key" 로 띄운다. 암호문은 Java BigInteger 의 부호 있는 2의 보수로 인코딩돼 있고, key 와 IV 가 정적 배열에 그대로 박혀 있다. openssl 로 그대로 복호해 키값 H3ll0 C0de3ngn 를 얻는다.
#dreamhack#ctf#reversing+6
2026-07-16
[🥉 Bronze 2] dream 은 노이즈인데 leet 문장이 숨어있다 — DreamHack Password in the gift box 풀이
blog

[🥉 Bronze 2] dream 은 노이즈인데 leet 문장이 숨어있다 — DreamHack Password in the gift box 풀이

chall.py 는 puzzle 을 "DH{}" 로 XOR 해 dream 을 만든 뒤, 그 안에서 leet 로 쓴 "the" 와 "iskey" 사이의 pw_key 를 뽑아 다시 XOR 한다. 문제는 두 빈칸(LEET_START, LEET_END)을 채우는 것. dream 을 아무리 봐도 th3·15k3y 같은 흔한 leet 는 안 나온다. 멀티문자 leet 치트시트를 곱집합으로 훑어야 "|"}{|=- 와 |$|(&`/ 가 튀어나온다.
#dreamhack#ctf#misc+4
2026-07-15
[🥉 Bronze 1] 밀려버린 BMP 헤더 되살리기 — DreamHack BMP Recovery 풀이
blog

[🥉 Bronze 1] 밀려버린 BMP 헤더 되살리기 — DreamHack BMP Recovery 풀이

헤더가 0으로 밀린 BMP 파일 하나를 준다. 살아남은 biBitCount(24) 하나로 픽셀 크기를 잡고, 행과 다음 행의 픽셀 차이가 최소인 지점으로 진짜 폭을 찾아 헤더를 재구성하면 그림 속 flag가 드러난다. "폭이 조금만 틀려도 이미지가 대각선으로 밀려 노이즈가 된다"는 성질을 역으로 이용한 포렌식 문제다.
#dreamhack#ctf#forensics+4
2026-07-15
[🥉 Bronze 2] FAT32 부트섹터를 읽어 플래그를 계산하다 — DreamHack VBR 풀이
blog

[🥉 Bronze 2] FAT32 부트섹터를 읽어 플래그를 계산하다 — DreamHack VBR 풀이

512바이트짜리 VBR(볼륨 부트 레코드) 하나가 전부인 포렌식 문제. 플래그는 파일에 박혀 있지 않고, 부트섹터 필드에서 계산해야 한다. 파일시스템 종류(FAT32→1), 볼륨 크기(총 섹터×섹터당 바이트), 볼륨 시리얼 번호를 각 오프셋에서 읽어 더하면 플래그가 나온다.
#dreamhack#ctf#forensics+3
2026-07-15
[🥉 Bronze 3] 이모지 단일치환을 영어 문맥으로 되짚기 — DreamHack emoji 풀이
blog

[🥉 Bronze 3] 이모지 단일치환을 영어 문맥으로 되짚기 — DreamHack emoji 풀이

플래그가 210자짜리 이모지 열로 바뀌어 있다. 26종의 이모지는 24개 알파벳과 중괄호에 일대일 대응된다. ⓜ️=m 힌트와 DH{ 접두사, 그리고 A·B·P·E·I 처럼 글자 모양을 그대로 담은 이모지를 앵커로 삼으면 절반이 뚫리고, 나머지는 "emoji"의 사전적 정의문이라는 영어 문맥이 강제로 채워 준다.
#dreamhack#ctf#misc+3
2026-07-15
[🥉 Bronze 3] IEND 뒤에 숨긴 암호문, 그리고 키를 역산한 Vigenère — DreamHack hidden_vigenere 풀이
blog

[🥉 Bronze 3] IEND 뒤에 숨긴 암호문, 그리고 키를 역산한 Vigenère — DreamHack hidden_vigenere 풀이

범죄 조직에게서 압수한 PNG는 겉보기엔 평범한 그림이다. 하지만 IEND 청크 뒤에 29바이트짜리 암호문이 꼬리처럼 붙어 있다. 플래그 형식이 bisc2024로 시작한다는 걸 알면, 암호문 앞머리로 Vigenère 키를 역산할 수 있고, 그 키로 전체를 복호하면 플래그가 나온다.
#dreamhack#ctf#misc+3
2026-07-15
[🥉 Bronze 2] 뒤집힌 base64 속에 숨은 JSFuck — DreamHack reverse_decoding 풀이
blog

[🥉 Bronze 2] 뒤집힌 base64 속에 숨은 JSFuck — DreamHack reverse_decoding 풀이

이메일로 받은 JPG가 열리지 않는다. 앞부분의 널 바이트를 걷어 내면 파일이 통째로 뒤집혀 있고, 머리에 붙은 base64는 padding이 앞에 온 역순 문자열이다. 뒤집어 디코드하면 JSFuck이 나오고, 이를 실행하는 대신 eval을 가로채면 플래그가 그대로 드러난다.
#dreamhack#ctf#misc+3
2026-07-15
[🥈 Silver 4] add·rotate·xor 블록암호를 정적 역산 — DreamHack My ARX Cipher 풀이
blog

[🥈 Silver 4] add·rotate·xor 블록암호를 정적 역산 — DreamHack My ARX Cipher 풀이

stripped ELF 하나가 12바이트 key로 flag.enc를 만들어 놓았다. 블록 함수를 objdump로 뜯어 4바이트(16bit 워드 v0·v1)에 rotate-add-xor-swap을 3라운드 도는 ARX 구조임을 밝히고, 각 연산을 역으로 되감아 flag를 복원한다. gdb 런타임과 재암호화 라운드트립으로 이중 검증.
#dreamhack#ctf#reversing+5
2026-07-15
[🥈 Silver 2] rank 이 부족한 행렬로 암호화된 flag — DreamHack Squared Flag 풀이
blog

[🥈 Silver 2] rank 이 부족한 행렬로 암호화된 flag — DreamHack Squared Flag 풀이

64바이트 flag 를 벡터로 보고 공개된 64×64 행렬 M 을 곱해 mod 65537 한 결과만 준다. 선형변환이니 역행렬을 곱하면 끝일 것 같지만, M 은 mod 65537 에서 rank 가 60 밖에 안 돼 역행렬이 없다. 널공간 차원 4 와 알려진 평문 "DH{ … }" 4바이트를 함께 걸어 해를 유일하게 못 박아 복원했다.
#dreamhack#ctf#crypto+4
2026-07-14
[🥈 Silver 3] 같은 N, 두 지수로 암호화된 RSA — DreamHack uncommon e 풀이
blog

[🥈 Silver 3] 같은 N, 두 지수로 암호화된 RSA — DreamHack uncommon e 풀이

같은 모듈러스 N 아래 같은 평문을 서로 다른 두 지수 e1, e2 로 암호화한 RSA 문제. 출제자가 e 를 일부러 φ(N) 과 공약수를 갖게 골라 개별 복호를 막았지만, gcd(e1, e2)=1 이라 공통 모듈러스 공격이 그대로 통한다. 확장 유클리드로 a·e1 + b·e2 = 1 을 구해 c1^a·c2^b 로 평문을 복원했다.
#dreamhack#ctf#crypto+3
2026-07-14
[🥈 Silver 4] e가 너무 크면 d가 작다 — DreamHack RSA-wiener 풀이
blog

[🥈 Silver 4] e가 너무 크면 d가 작다 — DreamHack RSA-wiener 풀이

공개키의 공개지수 e가 모듈러스 N만큼이나 크다는 건 개인지수 d가 아주 작다는 신호다. Wiener's attack으로 e/N을 연분수 전개하고, 그 수렴(convergent) 중에서 진짜 d를 골라내 N을 인수분해하고 암호문을 복호했다. SageMath로 수렴 과정을 직접 훑어 확인한다.
#dreamhack#ctf#crypto+4
2026-07-14
[🥉 Bronze 2] 찢어진 종이 2024장에서 카이사르 조각 맞추기 — DreamHack 누가 카이사르를 화나게 했을까? 풀이
blog

[🥉 Bronze 2] 찢어진 종이 2024장에서 카이사르 조각 맞추기 — DreamHack 누가 카이사르를 화나게 했을까? 풀이

플래그가 든 종이를 찢어 2024장으로 흩뿌린 카이사르 문제. 대부분은 기호 미끼이고, 커스텀 알파벳으로만 이뤄진 여덟 조각이 진짜다. 정해진 알파벳으로 시프트 11만큼 복호한 뒤 어순에 맞게 조립하면 플래그가 된다. 플래그 형식이 흔한 DH가 아니라는 함정도 있었다.
#dreamhack#ctf#crypto+2
2026-07-14
[🥉 Bronze 3] 로마자 일본어를 단일치환으로 가린 매칭 퍼즐 — DreamHack Easy Linguistics 풀이
blog

[🥉 Bronze 3] 로마자 일본어를 단일치환으로 가린 매칭 퍼즐 — DreamHack Easy Linguistics 풀이

일본어 명사를 로마자로 적은 뒤 단일치환으로 암호화한 여섯 단어를, 각각의 뜻에 짝짓는 언어학 퍼즐. 두 단어가 공유하는 접미사를 앵커로 삼아 치환표를 세우면 yoasobi·yokaze·yamiyo 같은 원래 단어가 복원된다. 처음엔 글자 두 개가 빈칸으로 남았지만, 나머지 대응을 채우자 마지막 단어까지 tobihi(飛び火, 튀는 불티)라는 진짜 일본어 단어로 딱 떨어졌다. 맞춘 순서가 곧 플래그가 된다.
#dreamhack#ctf#misc+3
2026-07-14
[🥉 Bronze 4] 보이지 않는 방향 표시 문자에 숨긴 플래그 — DreamHack 보이는 게 다가 아니다 풀이
blog

[🥉 Bronze 4] 보이지 않는 방향 표시 문자에 숨긴 플래그 — DreamHack 보이는 게 다가 아니다 풀이

README 한 줄이 전부인 미스크 문제. 글자 사이사이에 눈에 보이지 않는 U+200E(왼쪽에서 오른쪽 마크)가 잔뜩 흩뿌려져 있어, 화면으로는 알 수 없다. 심지어 터미널에 그냥 cat으로 띄워도 육안으로는 멀쩡한 플래그처럼 보인다 — 그대로 복사해서 제출하면 숨은 문자 때문에 오답이 된다. 파일에서 ASCII 문자만 남기면 진짜 플래그가 드러난다.
#dreamhack#ctf#misc+3
2026-07-14
[🥉 Bronze 2] 부분 문자열로 흩어 놓은 배치 난독화 되돌리기 — DreamHack Batch Checker 풀이
blog

[🥉 Bronze 2] 부분 문자열로 흩어 놓은 배치 난독화 되돌리기 — DreamHack Batch Checker 풀이

검사 로직을 윈도우 배치 파일로 난독화한 리버싱 문제. 100자짜리 무의미한 이름의 변수 37개를 정의한 뒤 %VAR:~offset,1% 부분 문자열 문법으로 한 글자씩 뽑아 7,463자짜리 명령 한 줄을 조립한다. 이 치환을 프로그램으로 풀면 원래의 비교식이 드러나고, 비교 대상이 곧 플래그다. "실행만 하면 된다"는 문제 설명과 달리, 실행하지 않고 정적으로 풀어야 안전하다.
#dreamhack#ctf#reversing+3
2026-07-14
[🥉 Bronze 2] 세 겹으로 포장한 귤 상자 벗기기 — DreamHack 감귤 포장하기 풀이
blog

[🥉 Bronze 2] 세 겹으로 포장한 귤 상자 벗기기 — DreamHack 감귤 포장하기 풀이

플래그를 wrap(아핀 곱셈)·box(위치별 XOR)·truck(뒤집은 테이블 base64) 세 변환으로 포장한 문제. 문제 설명 자체가 4컷 만화로 "즙 짜고 양념 치기 → 마구잡이로 섞고 테이프로 감기 → 뒤죽박죽 글자 트럭에 싣기 → 배송 완료"를 그려 놓았다. 세 변환이 모두 가역이라, 적용된 역순으로 base64를 풀고 XOR를 되돌리고 아핀을 역산하면 플래그가 나온다.
#dreamhack#ctf#crypto+4
2026-07-14
[🥉 Bronze 1] 귤 뒤에 숨긴 제로폭 문자 비트 — DreamHack 🍊귤귤귤 풀이
blog

[🥉 Bronze 1] 귤 뒤에 숨긴 제로폭 문자 비트 — DreamHack 🍊귤귤귤 풀이

귤 이모지가 잔뜩 늘어선 텍스트가 전부인 문제. 각 🍊 뒤에 눈에 보이지 않는 제로폭 문자 4개가 붙어 있고, 네 종류의 제로폭 문자가 2비트씩 = 1바이트를 이룬다. 그 바이트를 XOR 0x37로 복호하면 플래그가 나온다. "제1회 감귤 CTF"에 출제된 문제로, 문제 설명조차 귤 이모지로만 채워져 있다.
#dreamhack#ctf#crypto+3
2026-07-14
[🥉 Bronze 2] 공유 소수가 GCD로 새는 1000개의 RSA — DreamHack Common things between us 풀이
blog

[🥉 Bronze 2] 공유 소수가 GCD로 새는 1000개의 RSA — DreamHack Common things between us 풀이

1000개의 RSA 암호문과 모듈러를 주는 문제. 각 모듈러는 네 소수의 곱이고, 각 소수는 정확히 네 개의 모듈러에 공유된다. 두 모듈러의 최대공약수로 공유 소수를 캐내 전부 인수분해하고, 모든 평문을 복호해 XOR하면 플래그가 나온다. 단, 모든 쌍을 O(n²)으로 대조하면 1000개 기준으로 실제 20초 넘게 걸린다 — 실무에서 대규모 키 집합을 감사할 때는 이 방식이 그대로는 안 통한다.
#dreamhack#ctf#crypto+3
2026-07-14
[🥉 Bronze 1] 두 순열로 만든 clock 키스트림 되맞추기 — DreamHack Basic of crypto 풀이
blog

[🥉 Bronze 1] 두 순열로 만든 clock 키스트림 되맞추기 — DreamHack Basic of crypto 풀이

플래그 64바이트를 clock 제너레이터가 만든 키스트림과 XOR한 문제. 키스트림 값은 두 순열 H, M으로 keystream[i] = 8·H[i//8] + M[i%8] 처럼 결정되는데, 알려진 평문(DH{, }, 대문자와 밑줄만) 제약이 강해 순열을 전수조사하면 유일한 플래그가 복원된다. 실제로 40320가지 H 순열 중 39092번째에서 정답이 나오고, 걸린 시간은 0.14초뿐이다.
#dreamhack#ctf#crypto+4
2026-07-14
[🥉 Bronze 2] 두 모듈러의 소수 차이로 여는 인수분해 — DreamHack Is it CRT-RSA? 풀이
blog

[🥉 Bronze 2] 두 모듈러의 소수 차이로 여는 인수분해 — DreamHack Is it CRT-RSA? 풀이

플래그를 두 벌의 RSA로 절반씩 암호화하고, 두 모듈러의 소수 차이 dp·dq를 힌트로 주는 문제. 두 모듈러 관계식을 전개하면 한 소수에 대한 2차방정식이 되고, 근의 공식으로 소인수를 구하면 두 모듈러를 모두 인수분해해 복호할 수 있다. dp·dq는 소수 자체와 맞먹는 크기라 두 소수가 실제로 가깝지도 않은데도 정확한 차이값 하나만으로 인수분해가 그대로 뚫린다.
#dreamhack#ctf#crypto+3
2026-07-14
[🥉 Bronze 2] 코드에 박혀 버린 소인수 — DreamHack safeprime 풀이
blog

[🥉 Bronze 2] 코드에 박혀 버린 소인수 — DreamHack safeprime 풀이

안전소수(safe prime)를 쓴다며 RSA 두 벌로 플래그를 절반씩 암호화한 문제. 그런데 소수 생성 함수가 p1을 매 반복마다 고정 상수로 덮어써, 사실상 한 소인수가 소스에 공개돼 있다. N을 그 소수로 나누면 나머지 소인수가 나와 두 RSA를 모두 복호할 수 있다. sympy로 확인해보면 이 상수는 진짜 안전소수 조건(p, 2p+1 모두 소수)을 만족한다 — 문제는 성질이 아니라 그 값이 절대 바뀌지 않는다는 것이다.
#dreamhack#ctf#crypto+3
2026-07-14
[🥉 Bronze 3] 38겹으로 감싼 Base64 벗기기 — DreamHack What is This??? 풀이
blog

[🥉 Bronze 3] 38겹으로 감싼 Base64 벗기기 — DreamHack What is This??? 풀이

하나의 긴 문자열만 주고 무엇이냐고 묻는 crypto 문제. Base64로 인코딩한 결과를 다시 Base64로, 또 그 결과를 Base64로... 38번 겹쳐 감싼 것이라, 디코드 결과가 더 이상 Base64가 아닐 때까지 반복해서 벗기면 플래그가 나온다. 원본 파일은 100만 바이트가 넘는데, 겹마다 25%씩 줄어들어 최종 flag는 15바이트로 끝난다.
#dreamhack#ctf#crypto+3
2026-07-14
[🥉 Bronze 2] Duff's device로 펼친 위치별 XOR 되돌리기 — DreamHack legacyopt 풀이
blog

[🥉 Bronze 2] Duff's device로 펼친 위치별 XOR 되돌리기 — DreamHack legacyopt 풀이

입력을 Duff's device로 펼친 루프에서 위치별 상수와 XOR해 hex로 출력하는 인코더 문제. 각 출력 바이트가 그 자리 입력에만 달려 있어, 같은 길이의 알려진 입력을 한 번 넣어 위치별 XOR 상수를 캐낸 뒤 주어진 출력에 그대로 적용하면 플래그가 복원된다. 재인코딩이 원본과 일치함까지 확인했다.
#dreamhack#ctf#reversing+4
2026-07-14
[🥉 Bronze 3] XOR·덧셈·비트회전을 거꾸로 되짚다 — DreamHack nub_rev01 풀이
blog

[🥉 Bronze 3] XOR·덧셈·비트회전을 거꾸로 되짚다 — DreamHack nub_rev01 풀이

입력 한 글자씩 XOR·덧셈·비트회전을 걸어 스택에 박힌 상수와 비교하는 리버싱 크랙미. 세 연산이 모두 가역이라, 비교 대상(target)에서 역순으로 회전을 풀고 덧셈을 빼고 XOR를 되돌리면 정답 입력이 그대로 복원된다. 복원한 문자열을 바이너리에 넣어 Correct로 확인했다.
#dreamhack#ctf#reversing+4
2026-07-14
[🥉 Bronze 2] 거듭제곱 차이 한 줄로 평문을 되돌리다 — DreamHack ICM2022 풀이
blog

[🥉 Bronze 2] 거듭제곱 차이 한 줄로 평문을 되돌리다 — DreamHack ICM2022 풀이

평문을 두 키의 거듭제곱 차이에 곱해 암호문 하나로 내보내는 crypto 문제. 키가 두 개지만 하나는 공개되고 다른 하나는 좁은 범위라, 암호문이 정수로 떨어지는 키를 전수조사하면 평문 정수 p가 그대로 복원된다. 그 p 자체가 플래그이며, ord 값을 이어 붙인 형태라 사람이 읽을 수도 있다.
#dreamhack#ctf#crypto+3
2026-07-14
[🥉 브론즈 2] 입력할 수 없는 정답 — DreamHack My Favorite Fruit 풀이
blog

[🥉 브론즈 2] 입력할 수 없는 정답 — DreamHack My Favorite Fruit 풀이

과일 이름을 물어보는 챗봇 바이너리다. 다섯 과일을 다 맞히면 전역 버퍼를 flag 로 복원해 출력하는데, scanf 포맷이 %9s 라 열 글자짜리 strawberry 는 아홉 글자로 잘려 절대 매칭되지 않는다. 그래서 런타임으로는 flag 가 나오지 않는다. 하지만 버퍼를 만드는 연산이 XOR 라 순서와 무관하므로, 다섯 과일 키를 정적으로 한꺼번에 XOR 해 flag 를 복원했다.
#dreamhack#ctf#reversing+4
2026-07-13
[🥉 Bronze 3] smali에 흩어 둔 상수로 조립되는 플래그 — DreamHack Summer Fan 풀이
blog

[🥉 Bronze 3] smali에 흩어 둔 상수로 조립되는 플래그 — DreamHack Summer Fan 풀이

APK를 apktool로 뜯어 smali를 읽는 안드로이드 리버싱 문제. 플래그는 32개 정수 리스트 FLAG와 한 글자씩 쪼개 놓은 문자열 KEY를 XOR·뺄셈으로 조합해 만든다. gen(i) 보정항까지 그대로 재현하면 BISC 형식의 플래그가 복원된다.
#dreamhack#ctf#reversing+4
2026-07-13
[🥉 Bronze 3] 원형 리스트 인코더를 블랙박스로 뒤집다 — DreamHack tiny-ouroboroi 풀이
blog

[🥉 Bronze 3] 원형 리스트 인코더를 블랙박스로 뒤집다 — DreamHack tiny-ouroboroi 풀이

입력 각 글자를 그 글자값 길이의 원형 연결리스트로 만들어 회전·토글한 뒤 비트를 모아 한 바이트씩 출력하는 인코더 문제. 출력의 각 바이트가 오직 그 자리 글자와 위치에만 의존하므로, 함수를 다 역산할 필요 없이 후보 글자를 통째로 넣어 위치별 매핑을 만들면 플래그가 복원된다.
#dreamhack#ctf#reversing+3
2026-07-13
[🥉 Bronze 4] 이름만 다른 같은 파일 두 개 — DreamHack 어 왜 두 번 써지지 풀이
blog

[🥉 Bronze 4] 이름만 다른 같은 파일 두 개 — DreamHack 어 왜 두 번 써지지 풀이

이름이 거의 같은(하나는 확장자 앞에 공백이 하나 더) 텍스트 파일 두 개를 주는 미스크 문제. 두 파일은 바이트 단위로 완전히 동일하고, 그 안에 플래그가 그대로 두 번 적혀 있다. 숨긴 것도 인코딩도 없이 그냥 읽으면 된다. 덧붙여 zip 헤더와 Windows 이름 정규화로 "이 공백이 끝에 붙은 게 아니라 가운데 있다"는 것까지 확인하고, 같은 문제가 드림핵에 두 번 등록돼 있다는 것도 API 로 대조해 봤다.
#dreamhack#ctf#misc+1
2026-07-13
[🥉 Bronze 3] 주기 16 비제네르를 열별 빈도로 깨다 — DreamHack EVER-igen 풀이
blog

[🥉 Bronze 3] 주기 16 비제네르를 열별 빈도로 깨다 — DreamHack EVER-igen 풀이

62자 알파벳 위에서 16글자 키로 돌아가는 비제네르 암호. 키공간이 62^16이라 전수조사는 불가능하지만, 같은 키를 쓰는 자리끼리 16개 열로 나누면 각 열은 단일 시프트 문제가 된다. 영어 평문은 소문자가 압도적이라, 열마다 소문자 빈도를 최대로 만드는 시프트가 곧 그 자리의 키다.
#dreamhack#ctf#crypto+3
2026-07-13
[🥉 Bronze 4] 뒤집힌 문자열 한 줄 — DreamHack Do not fight 풀이
blog

[🥉 Bronze 4] 뒤집힌 문자열 한 줄 — DreamHack Do not fight 풀이

텍스트 파일 하나를 주는 미스크 문제. 내용이 통째로 뒤집혀 있어 rev 한 번이면 플래그가 나온다. 플래그 형식이 DH가 아니라 AF로 시작하고, 문구 자체가 도구(CyberChef)를 쓰라는 농담이다. 문제 설명에 "AI로 리버싱 문제를 돌린다"를 놀리는 커뮤니티 캡처까지 박아놔서, 풀이보다 그 맥락이 더 재밌다.
#dreamhack#ctf#misc+2
2026-07-13
[🥉 Bronze 4] JPEG 뒤에 붙은 ZIP 꺼내기 — DreamHack Hefty Image 풀이
blog

[🥉 Bronze 4] JPEG 뒤에 붙은 ZIP 꺼내기 — DreamHack Hefty Image 풀이

이미지 파일 하나를 주는 포렌식 문제. JPEG 끝(FF D9) 뒤에 ZIP이 통째로 이어 붙어 있어, 뷰어로는 그냥 그림이지만 unzip으로 열면 flag.txt가 나온다. ZIP은 파일 끝부터 읽는 구조라 앞에 무엇이 붙어도 그대로 열린다는 성질을 이용한 전형적인 연결(concatenation) 스테가노그래피다. flag.txt가 무압축(Stored)으로 저장돼 있어 헥스덤프만으로도 내용이 그대로 읽힌다.
#dreamhack#ctf#forensics+2
2026-07-13
[🥉 Bronze 3] 16비트 시드짜리 스트림 암호 전수조사 — DreamHack STREAMer-Prototype 풀이
blog

[🥉 Bronze 3] 16비트 시드짜리 스트림 암호 전수조사 — DreamHack STREAMer-Prototype 풀이

16비트 상태를 비트 회전시켜 키스트림을 만드는 스트림 암호로 플래그를 XOR한 문제. 시드가 getrandbits(16)이라 경우의 수가 65,536개뿐이고, 플래그가 DH로 시작한다는 조건으로 정답 시드를 가려낸다. 실제로 전수조사를 돌려보면 65536개 중 접두사 조건을 만족하는 시드는 정확히 하나뿐이라, 우연히 걸릴 위험 없이 확실하게 정답이 가려진다.
#dreamhack#ctf#crypto+3
2026-07-13
[🥉 Bronze 4] 최대공약수로 새어 나온 XOR 키 — DreamHack 이동혁 놀아주기 풀이
blog

[🥉 Bronze 4] 최대공약수로 새어 나온 XOR 키 — DreamHack 이동혁 놀아주기 풀이

플래그를 상수 키로 XOR해 숨기고, 그 키에 서로소인 두 수를 곱한 a·b를 힌트로 주는 문제. gcd(a, b) = key · gcd(x, y) = key 이므로 두 곱의 최대공약수가 곧 XOR 키다. 유클리드 호제법을 손으로 직접 따라가며 508153과 610791의 gcd가 73으로 수렴하는 과정을 확인하고, 그 키로 enc를 XOR하면 플래그가 나온다.
#dreamhack#ctf#crypto+3
2026-07-13
[🥉 Bronze 4] 입력을 XOR해 비교하는 검사식 뒤집기 — DreamHack Happy New Year! 풀이
blog

[🥉 Bronze 4] 입력을 XOR해 비교하는 검사식 뒤집기 — DreamHack Happy New Year! 풀이

59자 입력을 코드에 박힌 상수 버퍼로 XOR한 뒤 고정 문자열과 strcmp하는 리버싱 문제. 비교식을 뒤집으면 정답 입력 = buf ^ s2 이고, 그 입력이 그대로 플래그 본문이 된다. 상수 버퍼를 재구성해 XOR 한 번으로 새해 인사 문장을 복원했다.
#dreamhack#ctf#reversing+3
2026-07-13
[🥉 Bronze 4] 비교식을 뒤집어 키를 복원하다 — DreamHack Easy Assembly 풀이
blog

[🥉 Bronze 4] 비교식을 뒤집어 키를 복원하다 — DreamHack Easy Assembly 풀이

손으로 짠 어셈블리 크랙미. check_password가 입력을 len과 enc_flag로 XOR해 0인지 검사하는데, 이 비교식을 뒤집으면 정답 키 = enc_flag ^ len 이다. 키 길이가 48이라 enc_flag를 0x30으로 XOR하면 플래그가 바로 나오고, 그 키를 넣으면 "You nailed it!"으로 확인된다.
#dreamhack#ctf#reversing+3
2026-07-13
[🥉 Bronze 4] 키 공간이 62,500뿐인 아핀 암호 — DreamHack Affe!n 풀이
blog

[🥉 Bronze 4] 키 공간이 62,500뿐인 아핀 암호 — DreamHack Affe!n 풀이

비밀 문장을 GF(251) 위 아핀 암호로 가린 문제. 키가 두 바이트(각 1~250)뿐이라 가능한 키쌍이 62,500개에 불과하고, 평문에 "cryptography"가 들어 있다는 조건으로 유일 키를 특정할 수 있다. 전수조사로 키를 찾아 복호하면 문장 끝에 플래그가 나온다.
#dreamhack#ctf#crypto+3
2026-07-13
[🥉 Bronze 4] 4바이트 키가 부순 RSA — DreamHack TOP secret! 풀이
blog

[🥉 Bronze 4] 4바이트 키가 부순 RSA — DreamHack TOP secret! 풀이

플래그는 4바이트 키의 Vigenère로, 그 키는 RSA(e=5)로 암호화해 건네주는 문제. 키가 32비트뿐이라 key^5이 2048비트 N보다 훨씬 작아 모듈러 축약이 일어나지 않는다. enc2의 정수 5제곱근으로 키를 복원하고, 그 키로 Vigenère 덧셈을 되돌리면 플래그가 나온다.
#dreamhack#ctf#crypto+3
2026-07-13
[🥉 Bronze 4] 만들어 놓고 버린 반환값에서 플래그를 낚아채다 — DreamHack Check Return Value 풀이
blog

[🥉 Bronze 4] 만들어 놓고 버린 반환값에서 플래그를 낚아채다 — DreamHack Check Return Value 풀이

main이 플래그를 버퍼에 조립해 반환하지만, 그 반환값을 쓰지 않고 곧바로 다른 문자열로 덮어써 출력하지 않는 리버싱 문제. 반환값을 덮어쓰기 직전 지점에 gdb 브레이크포인트를 걸고 $rax를 문자열로 읽으면 플래그가 그대로 나온다.
#dreamhack#ctf#reversing+3
2026-07-13
[🥉 브론즈 3] XOR 한 줄로 잠근 랜섬웨어, 키를 거꾸로 뽑아내다 — DreamHack darimchal_001 풀이
blog

[🥉 브론즈 3] XOR 한 줄로 잠근 랜섬웨어, 키를 거꾸로 뽑아내다 — DreamHack darimchal_001 풀이

입력한 복호화 키를 고정 KEY와 XOR해 JOKER 상수와 strncmp하는 랜섬웨어 콘셉트 문제. XOR은 자기역원이라 JOKER ⊕ KEY를 그대로 계산하면 통과 비밀번호 pa55uc0_가 나온다. 마지막에 플래그를 DH{} 없이·언더바를 빼고 pa55uc0로 내야 정답으로 인정되는 함정이 있었다.
#dreamhack#ctf#crypto+4
2026-07-13
[🥈 실버 3] 커스텀 base64를 알려진 평문으로 복원하다 — DreamHack baseball 풀이
blog

[🥈 실버 3] 커스텀 base64를 알려진 평문으로 복원하다 — DreamHack baseball 풀이

baseball 바이너리는 table 파일의 64글자를 알파벳으로 쓰는 커스텀 base64 인코더다. 정작 table은 주어지지 않지만, 평문 text_in과 그 인코딩 text_out이라는 알려진 쌍이 있다. 표준 base64의 위치별 6비트 값에 text_out 문자를 대응시켜 알파벳을 복원하고, 같은 알파벳으로 flag_out을 복호했다.
#dreamhack#ctf#reversing+4
2026-07-13
[🌱 새싹] 바이트 Caesar를 255개 키로 뚫기 — DreamHack ByteCaesar 풀이
blog

[🌱 새싹] 바이트 Caesar를 255개 키로 뚫기 — DreamHack ByteCaesar 풀이

secret 문장을 바이트 단위 Caesar로 암호화한 결과만 주어진다. 키는 랜덤이지만 1~255 사이 한 바이트라 경우의 수가 255개뿐이다. 각 키로 복호해 결과가 전부 인쇄 가능한 ASCII이고 DH가 들어간 키를 찾으면 된다. 함께 준 secret 파일은 가짜라, output.txt의 암호문을 전수조사해 진짜 플래그를 꺼냈다.
#dreamhack#ctf#crypto+3
2026-07-13
[🥉 브론즈 4] 암호화된 이미지를 되살리다 — DreamHack Recover 풀이
blog

[🥉 브론즈 4] 암호화된 이미지를 되살리다 — DreamHack Recover 풀이

chall 바이너리가 flag.png를 바이트마다 암호화해 encrypted 파일로 저장한다. 암호화는 4바이트 키 deadbeef로 XOR한 뒤 0x13을 더하는 단순 가역 연산이라, 순서를 반대로 되돌리면 원본이 복구된다. 복구본의 첫 8바이트가 PNG 시그니처와 일치하는 걸 확인하고, 되살린 이미지 속 플래그를 읽었다.
#dreamhack#ctf#reversing+4
2026-07-13
[🥉 브론즈 4] 928개 함수에 흩어진 글자 모으기 — DreamHack Collect Me 풀이
blog

[🥉 브론즈 4] 928개 함수에 흩어진 글자 모으기 — DreamHack Collect Me 풀이

func_0부터 func_927까지 928개 함수가 각각 char 지역변수 하나에 한 바이트씩 담고 있다. main은 이 함수들을 호출하지 않고 안내만 출력하므로, 실행이 아니라 objdump로 각 함수의 즉시값을 번호순으로 긁어 928자 문자열을 조립했다. 그 Lorem ipsum 본문 속에 플래그가 숨어 있었다.
#dreamhack#ctf#reversing+4
2026-07-13
[🥉 브론즈 4] 겹겹이 인코딩된 base64 벗기기 — DreamHack Base64 10 Times 풀이
blog

[🥉 브론즈 4] 겹겹이 인코딩된 base64 벗기기 — DreamHack Base64 10 Times 풀이

문제 설명에 긴 base64 문자열 하나만 주어진다. 디코드하면 또 base64, 다시 디코드해도 또 base64 — 여러 겹으로 인코딩돼 있다. 매 층 결과가 여전히 인쇄 가능한 base64라, 플래그가 보일 때까지 반복 디코드하면 된다. 열한 번 벗기니 플래그가 나왔다.
#dreamhack#ctf#crypto+3
2026-07-13
[🥉 브론즈 3] 출력되지 않는 flag를 함수 인자에서 훔치다 — DreamHack Check Function Argument 풀이
blog

[🥉 브론즈 3] 출력되지 않는 flag를 함수 인자에서 훔치다 — DreamHack Check Function Argument 풀이

main이 어떤 함수를 flag 문자열 주소를 인자로 넘겨 호출하지만, 그 함수는 flag를 출력하지 않는다. 게다가 flag는 바이너리에 평문으로 없고 생성자가 런타임에 조립한다. x86-64 호출 규약상 첫 인자는 rdi이므로, 그 함수 호출 지점에 GDB 브레이크를 걸고 rdi를 읽어 flag를 그대로 가로챘다.
#dreamhack#ctf#reversing+4
2026-07-13
[🥉 브론즈 3] 세 나머지를 합쳐 flag를 되살리다 — DreamHack chinese what? 풀이
blog

[🥉 브론즈 3] 세 나머지를 합쳐 flag를 되살리다 — DreamHack chinese what? 풀이

flag를 정수로 본 뒤 세 개의 420비트 소수로 나눈 나머지만 공개된 crypto 문제. 나머지 하나로는 flag가 소수보다 커서 복원되지 않지만, 서로소인 세 소수의 곱이 flag보다 크므로 중국인의 나머지 정리(CRT)로 세 합동식을 합치면 flag가 유일하게 결정된다. CRT로 정수를 복원해 바이트로 되돌렸다.
#dreamhack#ctf#crypto+4
2026-07-13
[🥉 브론즈 1] CAN 버스 로그에서 훔친 차의 정체 — DreamHack Grand Theft Auto 풀이
blog

[🥉 브론즈 1] CAN 버스 로그에서 훔친 차의 정체 — DreamHack Grand Theft Auto 풀이

자동차 CAN 버스 캡쳐 candump.txt 한 개가 주어진다. 로그는 UDS 진단 세션으로, 진단기가 ReadDataByIdentifier(0x22)로 DID 0xF190(VIN)을 요청하고 ECU가 ISO-TP 멀티프레임으로 응답한다. 프레임을 재조립해 VIN을 얻고, 그 VIN을 연도·제조사·모델로 디코드해 플래그를 완성했다.
#dreamhack#ctf#forensics+4
2026-07-13
[🥉 브론즈 3] 세 단계 변환을 거꾸로 되돌리다 — DreamHack r-xor-t 풀이
blog

[🥉 브론즈 3] 세 단계 변환을 거꾸로 되돌리다 — DreamHack r-xor-t 풀이

입력 64자를 add·배열 뒤집기·xor 세 단계로 변환해 고정된 target과 strncmp하는 리버싱 문제. 세 연산이 모두 가역이라, target에서 xor 3을 풀고 배열을 다시 뒤집고 add 13을 되돌리면 올바른 입력이 그대로 복원된다. 그 입력이 곧 플래그 본문이고, 바이너리에 넣어 Nice!로 확인했다.
#dreamhack#ctf#reversing+4
2026-07-13
[🥉 브론즈 2] 응답 크기로 되감은 blind SQLi — DreamHack access-log 풀이
blog

[🥉 브론즈 2] 응답 크기로 되감은 blind SQLi — DreamHack access-log 풀이

access.log 하나만 주어진 포렌식 문제. 로그는 sqlmap이 DVWA에 던진 time-based blind SQLi로 가득하다. time-based의 원래 신호인 '지연'은 nginx 기본 로그에 없지만, 주입된 IF가 WHERE의 행 유무를 바꾸는 덕에 응답 바이트(1664 = 조건 참)가 오라클이 된다. 4977개 추출 쿼리의 ORD(MID()) 비교를 되감아 dvwa.flag.value = DH{...}를 복원했다.
#dreamhack#ctf#forensics+4
2026-07-13
[🥉 Bronze 1] 죽은 코드 속 Caesar 복호기를 되살리다 — DreamHack Small Counter 풀이
blog

[🥉 Bronze 1] 죽은 코드 속 Caesar 복호기를 되살리다 — DreamHack Small Counter 풀이

바이너리는 실행해도 카운터만 세고 끝난다. flag를 만드는 flag_gen은 counter==5일 때만 불리는데 루프가 0에서 끝나 절대 도달하지 않는 죽은 코드다. flag_gen이 알파벳 테이블로 Caesar 복호를 한다는 걸 읽어내고, 암호문 IM 접두가 DH 로 풀리는 shift=5를 확정한 뒤 그 로직을 재현해 flag를 복원했다. GDB로 실제 flag_gen을 직접 호출해 결과가 정확히 일치함을 확인했다.
#dreamhack#ctf#reversing+4
2026-07-13
[🌱 새싹] 이름은 base64, 정체는 base32 — DreamHack likeb64 풀이
blog

[🌱 새싹] 이름은 base64, 정체는 base32 — DreamHack likeb64 풀이

target.txt 안에 base64처럼 생긴 문자열 하나만 주어진다. 그런데 '=' 패딩이 3개고, 데이터 길이가 4의 배수에서 하나 어긋나며, 숫자와 +/ 기호가 하나도 없다. base64 규칙으로는 나올 수 없는 출력이다. 문제 설명이 흘린 32글자 알파벳을 단서로 이것이 커스텀 알파벳 base32(숫자 2-7 자리를 a-f로 바꾼 것)임을 밝히고, 알파벳만 되돌려 복호한다.
#dreamhack#ctf#crypto+4
2026-07-13
[🥉 Bronze 1] 공유키에 1을 넣으면 비밀이 1로 고정된다 — DreamHack Textbook-DH 풀이
blog

[🥉 Bronze 1] 공유키에 1을 넣으면 비밀이 1로 고정된다 — DreamHack Textbook-DH 풀이

교과서 그대로의 Diffie-Hellman에는 상대가 보낸 공개키를 검증하는 절차가 없다. 서버는 중간자가 넣는 키가 생성자 g(=2)와 같을 때만 거부하는데, 대신 1을 넣으면 sk = 1^x mod p = 1로 양쪽 공유비밀이 고정된다. AES 키가 md5("1")로 정해지므로 두 암호문을 그대로 복호해 flag를 이어붙였다.
#dreamhack#ctf#crypto+4
2026-07-13
[🥉 Bronze 2] 차단은 대소문자를 가리고 통과는 안 가린다 — DreamHack baby-Case 풀이
blog

[🥉 Bronze 2] 차단은 대소문자를 가리고 통과는 안 가린다 — DreamHack baby-Case 풀이

nginx가 /shop을 정확히 막고 앱은 leg=='FLAG'를 막지만, nginx의 경로 매칭은 대소문자를 구분하고 Express 라우팅과 앱의 검색은 대소문자를 무시한다. 이 어긋남을 겹쳐, /Shop에 leg=flag를 보내 두 차단을 동시에 통과해 FLAG를 꺼냈다.
#dreamhack#ctf#web+5
2026-07-13
[🥉 Bronze 4] CSP를 뚫지 않고, 출력을 넘쳐 무너뜨리다 — DreamHack Broken Buffalo Wings 풀이
blog

[🥉 Bronze 4] CSP를 뚫지 않고, 출력을 넘쳐 무너뜨리다 — DreamHack Broken Buffalo Wings 풀이

반영 XSS에 CSP가 걸려 있지만, CSP를 설정하는 header()가 본문을 echo한 "뒤"에 있다. 재귀 str_replace가 반복마다 출력을 뱉는 걸 이용해 PHP output_buffering을 넘기면, 헤더가 먼저 나가버려 CSP header()가 실패한다. CSP가 사라진 페이지에서 XSS로 쿠키를 유출했다.
#dreamhack#ctf#web+5
2026-07-13
[🥈 Silver 1] Redis가 밥 먹듯 남기는 RDB로 웹셸을 굽다 — DreamHack phpMyRedis 풀이
blog

[🥈 Silver 1] Redis가 밥 먹듯 남기는 RDB로 웹셸을 굽다 — DreamHack phpMyRedis 풀이

Redis eval로 Lua를 돌리고 config로 CONFIG를 만질 수 있는 PHP 앱이다. Lua에서 SAVE는 막혀 있지만, CONFIG로 RDB 저장 위치를 웹 루트로 돌리고 save 정책을 "1초 1변경"으로 바꿔 자동 저장을 유도했다. RDB 덤프에 심은 <?php 웹셸로 RCE, 실행 전용 /flag를 돌려 flag를 얻었다.
#dreamhack#ctf#web+5
2026-07-13
[🥈 Silver 1] base 태그로 nonce 스크립트를 통째로 훔치다 — DreamHack CSP Bypass Advanced 풀이
blog

[🥈 Silver 1] base 태그로 nonce 스크립트를 통째로 훔치다 — DreamHack CSP Bypass Advanced 풀이

script-src 'self' 'nonce-…' 에 반영 XSS. 앞선 CSP Bypass는 /vuln이 입력을 raw로 돌려줘 자기-스크립트-가젯으로 풀렸지만, Advanced는 /vuln을 HTML로 감싸 그 길을 막았다. CSP에 base-uri가 없다는 틈을 파고들어, base 태그로 페이지의 정품 nonce 스크립트를 공격자 서버로 재해석시켜 임의 JS를 실행했다.
#dreamhack#ctf#web+5
2026-07-13
[🥉 Bronze 3] 메뉴판이 곧 정답 — DreamHack amocafe 풀이
blog

[🥉 Bronze 3] 메뉴판이 곧 정답 — DreamHack amocafe 풀이

카페 사이트가 좋아하는 메뉴라며 이상한 문자열을 보여주고, 그 "메뉴 번호"를 맞히면 flag를 준다. 알고 보면 그 문자열은 flag에서 잘라낸 19자리 숫자(org)의 16진수를 살짝 가린 것이다. nibble a는 "10", b는 "_"로만 바뀌어 있어 그대로 되짚으면 풀린다.
#dreamhack#ctf#web+4
2026-07-13
[🥈 Silver 2] nonce를 몰라도 뚫리는 CSP — DreamHack Client Side Template Injection 풀이
blog

[🥈 Silver 2] nonce를 몰라도 뚫리는 CSP — DreamHack Client Side Template Injection 풀이

파라미터가 HTML로 그대로 반영되지만 CSP가 인라인 스크립트를 nonce로 막는다. 그런데 script-src에 unsafe-eval과 ajax.googleapis.com이 함께 열려 있어, 거기서 AngularJS를 불러 CSTI로 코드를 실행한다. 봇의 flag 쿠키를 동일출처 /memo로 흘려 회수했다.
#dreamhack#ctf#web+5
2026-07-13
[🥉 Bronze 2] "1년 뒤에 알려줄게"를 1바이트로 앞당기기 — DreamHack Simple Patch Me 풀이
blog

[🥉 Bronze 2] "1년 뒤에 알려줄게"를 1바이트로 앞당기기 — DreamHack Simple Patch Me 풀이

한 시간씩 sleep하며 8760번(1년)을 세야 flag를 보여주는 바이너리다. 카운터 초기값 0을 8760으로 바꾸는 4바이트 패치 하나로 대기 루프를 건너뛴다. flag는 그 카운터 값으로 만든 키의 XOR이라, 값이 고정이니 정적으로도 계산된다.
#dreamhack#ctf#reversing+4
2026-07-13
[🥉 Bronze 2] 세션 쿠키가 pickle이면 그건 코드다 — DreamHack web-deserialize-python 풀이
blog

[🥉 Bronze 2] 세션 쿠키가 pickle이면 그건 코드다 — DreamHack web-deserialize-python 풀이

세션을 base64(pickle)로 주고받는 Flask 앱이다. check_session이 사용자가 준 값을 그대로 pickle.loads 한다. pickle은 역직렬화 중 객체의 __reduce__를 실행하므로, flag를 읽어 반환하는 객체를 dict에 심어 응답 화면에 flag를 그대로 띄웠다.
#dreamhack#ctf#web+5
2026-07-13
[🥉 Bronze 3] 7번 주무른 입력을 거꾸로 되감기 — DreamHack Simple Crack Me 2 풀이
blog

[🥉 Bronze 3] 7번 주무른 입력을 거꾸로 되감기 — DreamHack Simple Crack Me 2 풀이

32바이트 입력에 XOR·덧셈·뺄셈을 일곱 번 섞어 목표값과 비교하는 crackme다. 섞는 연산이 전부 바이트 단위 가역이라, 목표값에서 같은 연산을 역순으로 풀면 입력이 그대로 복원된다. 디스어셈블로 순서·키·상수를 읽어 되감았다.
#dreamhack#ctf#reversing+4
2026-07-13
[🥉 Bronze 2] dreamhack.exe에 심겨야 열리는 DLL — DreamHack Inject ME!!! 풀이
blog

[🥉 Bronze 2] dreamhack.exe에 심겨야 열리는 DLL — DreamHack Inject ME!!! 풀이

익스포트도 없는 DLL이 DllMain에서 호스트 프로세스명을 검사한다. 이름이 dreamhack.exe여야 flag를 계산하는데, 그 값은 프로세스명 첫 4바이트를 WELL512 PRNG 시드로 삼아 만든다. 프로세스명이 고정이라 flag는 실행 없이 정적으로 복원된다.
#dreamhack#ctf#reversing+5
2026-07-13
[🥈 Silver 3] level 파라미터 하나로 뚫는 SQLi — DreamHack baby-sqlite 풀이
blog

[🥈 Silver 3] level 파라미터 하나로 뚫는 SQLi — DreamHack baby-sqlite 풀이

uid·upw 는 따옴표로 감싸 막았지만 level 은 숫자 컨텍스트라 따옴표 없이 주입된다. 공백·콤마·admin·select·따옴표를 전부 거르는 블랙리스트를 /**/·char()||·VALUES 로 우회해 UNION 으로 admin 행을 위조, 로그인 없이 FLAG 를 받아낸다.
#dreamhack#ctf#web+4
2026-07-13
[🥈 Silver 4] 인접 힙 청크의 함수 포인터를 넘어 덮다 — DreamHack basic_heap_overflow 풀이
blog

[🥈 Silver 4] 인접 힙 청크의 함수 포인터를 넘어 덮다 — DreamHack basic_heap_overflow 풀이

ptr = malloc(0x20) 과 over = malloc(0x20) 이 힙에서 연속으로 잡히는데 scanf("%s", ptr) 에 길이 제한이 없다. ptr 청크를 지나 over 청크의 첫 멤버인 함수 포인터 over->table 까지 덮어, main 끝의 over->table() 호출을 get_shell 로 돌렸다. 오프셋은 타깃 glibc 2.23 기준 0x28(40) 이었고, 로컬 glibc 와 달라 한 번 헤맸다.
#dreamhack#ctf#pwnable+4
2026-07-12
[🥉 Bronze 3] base64 블록을 반칸 밀어 필터를 빠져나가다 — DreamHack Base64 based 풀이
blog

[🥉 Bronze 3] base64 블록을 반칸 밀어 필터를 빠져나가다 — DreamHack Base64 based 풀이

파일명을 base64로 받아 include하는 PHP 앱인데, 인코딩된 문자열에 flag·hp·../의 base64 조각이 있으면 막는다. flag.php의 정직한 base64는 그 조각을 그대로 품는다. 앞에 ./를 붙여 3바이트 블록 정렬을 반칸 밀면 조각이 쪼개져 필터가 통째로 헛돈다.
#dreamhack#ctf#web+5
2026-07-12
[🥉 Bronze 2] 회수 가능한 입금으로 코인 값을 흔들다 — DreamHack out of money 풀이
blog

[🥉 Bronze 2] 회수 가능한 입금으로 코인 값을 흔들다 — DreamHack out of money 풀이

DHD 코인 가격이 풀 잔고 비율(dhc_balance/dhd_balance)로만 정해지는데, 그 잔고를 바꾸는 입금이 음수 value로 전액 회수된다. 싸게 사둔 DHD를 DHC 대량 입금으로 값을 9배 띄운 뒤 되팔아 공짜 차익을 만들고, 대출을 상환해도 남는 코인으로 flag를 받았다.
#dreamhack#ctf#web+5
2026-07-12
[🥉 Bronze 3] 슬래시 하나로 열리는 flag.php — DreamHack simple-phparse 풀이
blog

[🥉 Bronze 3] 슬래시 하나로 열리는 flag.php — DreamHack simple-phparse 풀이

flag.php 는 parse_url() 로 뽑은 경로를 preg_match("/flag.php/i", $path) 로 검사해 직접 접근을 막는다. 요청 경로 앞에 슬래시를 하나 더 붙이면 parse_url 이 flag.php 를 호스트로 해석하고 path 는 빈 문자열이 된다. 필터가 보는 값이 사라지므로 그대로 통과해 flag 가 노출된다.
#dreamhack#ctf#web+4
2026-07-12
[🥉 Bronze 3] IHDR 높이를 줄여 숨긴 flag — DreamHack broken-png 풀이
blog

[🥉 Bronze 3] IHDR 높이를 줄여 숨긴 flag — DreamHack broken-png 풀이

PNG 의 IHDR 청크만 CRC 가 어긋나 있다. 이미지 높이를 512에서 256으로 줄여 아래 절반에 있던 flag 를 잘라 숨긴 것이다. IDAT 를 압축 해제하면 실제로 512행이 나오고, 저장된 CRC 로 원래 높이를 역산할 수도 있다. IHDR 의 height 4바이트를 원래 값으로 되돌리면 숨겨졌던 flag 가 드러난다.
#dreamhack#ctf#misc+4
2026-07-12
[🥉 Bronze 1] 게임을 하지 않고 목표 점수를 제출한다 — DreamHack [wargame.kr] fly me to the moon 풀이
blog

[🥉 Bronze 1] 게임을 하지 않고 목표 점수를 제출한다 — DreamHack [wargame.kr] fly me to the moon 풀이

Tunnel 이라는 자바스크립트 게임의 점수가 브라우저에서 계산돼 서버로 그대로 POST 된다. anti-cheat 토큰은 세션당 발급될 뿐 점수가 진짜 플레이로 나왔는지 검증하지 않는다. 게임을 할 필요 없이 목표 점수 31337 을 직접 제출하면 플래그가 나온다. 클라이언트를 믿으면 안 된다는 걸 보여주는 문제.
#dreamhack#ctf#web+4
2026-07-12
[🥉 Bronze 3] 리크 없이 스택으로 점프하기 — memset 반환값으로 ASLR을 우회하다 (DreamHack validator)
blog

[🥉 Bronze 3] 리크 없이 스택으로 점프하기 — memset 반환값으로 ASLR을 우회하다 (DreamHack validator)

실행 스택 + 버퍼 오버플로우인데 스택 주소를 흘릴 출력이 하나도 없다. 열쇠는 main 이 ret 하는 순간 rdi 가 buf 를 가리킨다는 것과, memset 이 첫 인자(dest)를 그대로 rax 로 반환한다는 것이다. memset(buf, 0x90, 184) 로 NOP 슬레드를 깔면서 rax=buf 를 얻고, call rax 로 스택을 실행한다. 주소 하드코딩이 하나도 없어 ASLR 이 켜져 있어도 뚫린다.
#dreamhack#ctf#pwnable+4
2026-07-11
[🥇 Gold 4] key 검사를 우회해 같은 청크를 두 번 free — DreamHack tcache_dup2 풀이
blog

[🥇 Gold 4] key 검사를 우회해 같은 청크를 두 번 free — DreamHack tcache_dup2 풀이

전편 tcache_dup 은 libc-2.27 이라 같은 청크를 그냥 두 번 free 하면 됐다. 여기(2.30)는 2.29 부터 들어간 tcache 이중 free 검사(key)가 막는다. free 된 청크를 다시 편집(UAF)해 key 를 0 으로 지워 검사를 우회하고, tcache 의 next 를 puts@got 로 덮어(poisoning) get_shell 을 써넣는다. tcache_get 의 key-clear 때문에 대상은 free@got 가 아니라 puts@got 여야 했던 함정까지.
#dreamhack#ctf#pwnable+4
2026-07-11
[🥈 Silver 1] nonce를 몰라도 XSS가 터진다 — DreamHack DOM XSS 풀이
blog

[🥈 Silver 1] nonce를 몰라도 XSS가 터진다 — DreamHack DOM XSS 풀이

CSP가 script-src에 nonce와 strict-dynamic을 걸어 인라인 스크립트도 onerror도 다 막는다. nonce는 매 응답마다 회전해서 값을 훔칠 수도 없다. 하지만 원시 HTML 주입점이 nonce가 붙은 jquery 스크립트보다 앞에 있어서, base 태그로 그 스크립트의 로드 origin을 내 서버로 돌려버리면 nonce 값을 몰라도 이미 붙은 nonce를 재활용해 내 JS가 실행된다. document.cookie를 동일출처 /memo에 적재해 회수했다.
#dreamhack#ctf#web+6
2026-07-12
[🥇 Gold 4] printf(buf) 한 줄로 전역 변수를 1337 로 — DreamHack Format String Bug 풀이
blog

[🥇 Gold 4] printf(buf) 한 줄로 전역 변수를 1337 로 — DreamHack Format String Bug 풀이

printf 에 사용자 입력을 형식 문자열로 그대로 넘기는 고전 버그. 64비트 PIE 라 %p 로 코드 주소를 먼저 흘려 base 를 복원하고, %n 으로 전역 changeme 에 1337 을 써넣어 system("/bin/sh") 를 연다. while(1) 루프 덕에 leak 과 write 를 두 번에 나눠 처리했다. 원격 glibc 는 leak 슬롯이 한 칸 앞이라 오프셋을 다시 잡아야 했던 삽질도 함께.
#dreamhack#ctf#pwnable+4
2026-07-11
[🌱 Sprout] 널 하나 빠졌을 뿐인데 flag 가 새어나온다 — DreamHack memory_leakage 풀이
blog

[🌱 Sprout] 널 하나 빠졌을 뿐인데 flag 가 새어나온다 — DreamHack memory_leakage 풀이

read 는 버퍼 끝에 널을 붙이지 않는다. 16바이트 name 을 널 없이 가득 채우면, printf("%s", name) 이 경계를 넘어 바로 뒤에 붙은 age 와 flag_buf 까지 읽어버린다. flag_buf 에는 case 3 이 /flag 를 미리 담아두니, 출력 한 번으로 flag 가 통째로 새어나온다. 오버플로우 없이 널 하나의 부재만으로 뚫는 메모리 유출.
#dreamhack#ctf#pwnable+4
2026-07-11
[🥉 Bronze 3] 저장된 EBP 한 바이트를 지워 셸을 연다 — DreamHack off_by_one_000 풀이
blog

[🥉 Bronze 3] 저장된 EBP 한 바이트를 지워 셸을 연다 — DreamHack off_by_one_000 풀이

read 는 널을 붙이지 않고 strcpy 는 널까지 복사한다. 이 어긋남을 이용해 256바이트를 가득 채우면 257번째 널이 저장된 EBP 의 최하위 바이트로 새어 들어간다. 한 바이트가 0이 되면서 프레임 포인터가 0x100 아래로 정렬되고, main 의 leave; ret 이 우리가 뿌려둔 get_shell 로 착지한다. 정렬에 따라 확률적이라 셸이 뜰 때까지 재시도했다.
#dreamhack#ctf#pwnable+4
2026-07-11
[🥈 Silver 1] 같은 청크를 두 번 free — DreamHack tcache_dup 풀이
blog

[🥈 Silver 1] 같은 청크를 두 번 free — DreamHack tcache_dup 풀이

free() 하고 전역 포인터를 안 지우는 데다 glibc 2.27 이라 double-free 검사도 없다. 같은 청크를 두 번 해제하면 tcache 리스트가 자기 자신을 가리키는 루프가 되고, 이걸 이용해 다음 할당의 fd 를 free@GOT 로 조작한다. no-PIE·Partial RELRO 라 leak 없이 free@GOT 에 get_shell 을 얹고 free 를 부르면 셸이 뜬다.
#dreamhack#ctf#pwnable+5
2026-07-11
[🥇 Gold 4] free 하고 포인터를 안 지웠다 — DreamHack Tcache Poisoning 풀이
blog

[🥇 Gold 4] free 하고 포인터를 안 지웠다 — DreamHack Tcache Poisoning 풀이

메뉴 네 개짜리 힙 문제. free() 뒤에도 전역 포인터를 그대로 두는 바람에 해제된 tcache 청크의 fd 를 마음대로 읽고 쓸 수 있다. no-PIE 라 주소가 고정인 &stdout 를 할당해 libc 를 흘리고, 같은 수법으로 __free_hook 에 system 을 얹어 "/bin/sh" 를 free 하면 셸이 뜬다. glibc 2.27 이라 double-free 검사도 없다.
#dreamhack#ctf#pwnable+5
2026-07-11
[🌱 Sprout] 한 바이트만 넘쳐도 셸이 열린다 — DreamHack off_by_one_001 풀이
blog

[🌱 Sprout] 한 바이트만 넘쳐도 셸이 열린다 — DreamHack off_by_one_001 풀이

read_str 안의 ptr[len] = 0 이 딱 한 바이트를 버퍼 밖으로 흘린다. 20바이트를 정확히 채워 넣으면 그 NUL 이 바로 뒤에 붙은 int age 의 최하위 바이트를 0으로 덮고, age == 0 분기가 열리며 get_shell 이 실행된다. 오버플로우 한 바이트로 분기 하나를 뒤집는 전형적인 off-by-one.
#dreamhack#ctf#pwnable+4
2026-07-09
[🥈 Silver 3] age가 fptr로 부활한다 — DreamHack uaf_overwrite 풀이
blog

[🥈 Silver 3] age가 fptr로 부활한다 — DreamHack uaf_overwrite 풀이

Human 구조체와 Robot 구조체가 우연히 크기가 같아 같은 tcache(0x30) bin을 공유한다. glibc 2.27의 tcache는 free() 시 청크 맨 앞(next 포인터)만 덮어쓰고 나머지는 그대로 두기 때문에, 자유로워진 Human의 age 필드가 재할당된 Robot의 함수 포인터(fptr) 자리에 그대로 되살아난다. 일반 one_gadget은 스택 정렬 문제로 전부 실패해서, execve 시스템콜 클러스터의 진입점을 직접 찾아 우회했다. gdb로 age가 fptr로 부활하는 순간을 런타임에서 직접 확인하고, unsorted bin 유출도 /proc의 실제 libc 베이스와 대조해 검증했다.
#dreamhack#ctf#pwnable+5
2026-07-08
[🥈 Silver 4] SQL 컬럼 트렁케이션으로 admin 계정 탈취 — DreamHack tmitter 풀이
blog

[🥈 Silver 4] SQL 컬럼 트렁케이션으로 admin 계정 탈취 — DreamHack tmitter 풀이

트위터 클론 tmitter 는 admin 으로 로그인해야 플래그가 나온다. 회원가입 중복 체크는 '정확 일치'만 막지만, id 컬럼 varchar(32) 를 넘는 "admin"+공백+"1" 을 넣으면 INSERT 때 뒤가 잘려 "admin"+공백으로 저장된다. MySQL 은 PADSPACE 콜레이션이라 끝 공백을 무시해 비교하므로 그 계정이 곧 admin 이 되어 로그인·플래그 획득. 로컬 MariaDB 로 메커니즘을 재현하고, 라이브에서 컬럼 길이까지 프로빙해 확정했다.
#dreamhack#ctf#web+6
2026-07-08
[🥉 Bronze 2] PHP 느슨한 비교로 로그인 우회 — DreamHack Type c-j 풀이
blog

[🥉 Bronze 2] PHP 느슨한 비교로 로그인 우회 — DreamHack Type c-j 풀이

check.php 는 (int)$input == $target 형태의 느슨한 비교(==)로 ID/PW 를 검사한다. PHP7 에서 정수와 문자열을 비교하면 문자열이 숫자로 변환된다. sha1("1")은 356 으로, 랜덤 ID 는 대개 0 으로 파싱되므로 input1=0000000000, input2=356aaaaa 로 로그인이 뚫려 플래그가 나온다.
#dreamhack#ctf#web+4
2026-07-08
[🥈 Silver 4] 줄 끝 공백에 숨은 플래그 — SNOW 스테가노그래피 (DreamHack Snowing! 풀이)
blog

[🥈 Silver 4] 줄 끝 공백에 숨은 플래그 — SNOW 스테가노그래피 (DreamHack Snowing! 풀이)

flag.txt 에는 미끼 DH{fake_snow} 뒤로 눈에 안 보이는 공백과 탭이 잔뜩 붙어 있다. 문제명 "Snowing!" 이 가리키는 SNOW 화이트스페이스 스테가노그래피다. 바이트/패턴을 시각화해 정체를 확인하고, 곁들여진 Snow.jpeg 가 함정임을 포렌식으로 배제한 뒤, stegsnow -C 로 복호해 Snow 반복 사이의 진짜 플래그를 꺼낸다.
#dreamhack#ctf#forensics+5
2026-07-08
[🥉 Bronze 2] AES S-box 블록 변환을 역산해 입력 복원 — DreamHack rev-basic-9 풀이
blog

[🥉 Bronze 2] AES S-box 블록 변환을 역산해 입력 복원 — DreamHack rev-basic-9 풀이

chall9.exe 는 입력을 8바이트 블록마다 16라운드 변환(AES S-box + ror + 덧셈 피드백)한 뒤 하드코딩된 target 과 memcmp 한다. S-box 가 전단사라 각 라운드가 가역이므로, 블록별로 역산하면 정답 입력이 그대로 복원된다. wine 으로 "Correct" 까지 확인.
#dreamhack#ctf#reversing+4
2026-07-08
[🥉 Bronze 4] 단일 바이트 XOR — 256개 키 전수 대입으로 뚫기 (DreamHack SingleByteXor 풀이)
blog

[🥉 Bronze 4] 단일 바이트 XOR — 256개 키 전수 대입으로 뚫기 (DreamHack SingleByteXor 풀이)

DyingMessage 파일에 담긴 23바이트 hex 암호문. 단일 바이트 XOR 이라 키 후보는 256개뿐이다. 플래그가 DH{ 로 시작한다는 사실(known-plaintext)로 키를 한 번에 복원하거나, 256개를 전수 대입해 프린터블하게 풀리는 유일한 키(0x10)를 찾으면 플래그가 나온다.
#dreamhack#ctf#crypto+5
2026-07-08
[🥉 Bronze 3] X-Forwarded-For 헤더로 커맨드 인젝션 — DreamHack what-is-my-ip 풀이
blog

[🥉 Bronze 3] X-Forwarded-For 헤더로 커맨드 인젝션 — DreamHack what-is-my-ip 풀이

"당신의 IP를 알려주는" 단순한 Flask 앱. 그런데 IP를 구할 때 X-Forwarded-For 헤더값을 bash -c "echo {ip}" 에 그대로 넣는다. 헤더에 ;cat /flag 를 실으면 명령이 그대로 실행되어 플래그가 나온다.
#dreamhack#ctf#web+5
2026-07-07
[🥉 Bronze 3] 반환 주소 대신 "열 파일 이름"을 덮는다 — DreamHack bof 풀이
blog

[🥉 Bronze 3] 반환 주소 대신 "열 파일 이름"을 덮는다 — DreamHack bof 풀이

scanf("%144s") 로 스택 버퍼를 넘치는 전형적인 오버플로 문제. 그런데 덮을 것은 반환 주소가 아니다. 버퍼 바로 아래에 read_cat() 이 open() 할 파일명 "./cat" 이 놓여 있어서, 그 자리를 "flag" 로 덮으면 프로그램이 알아서 flag 파일을 열어 출력한다. 버퍼와 파일명 사이 거리 0x80 만 맞추면 끝.
#dreamhack#ctf#pwn+5
2026-07-07
[💎 Diamond III] 키 없이 ECB 트래픽만으로 32바이트 플래그 복원 — DreamHack Too Many Questions 풀이
blog

[💎 Diamond III] 키 없이 ECB 트래픽만으로 32바이트 플래그 복원 — DreamHack Too Many Questions 풀이

32개 도커 워커가 공유 키로 ECB 암호화한 "스무고개(이진 탐색)" 트래픽만 담긴 pcap이 주어진다. 키는 없다. ECB의 결정성 덕분에 답변 암호블록 4종을 (op × y/n)으로 분해하고, 256개 str(N) 암호문을 임계행렬 seriation으로 정렬한 뒤, 이진 탐색의 시간 순서로 블록 내 모호성을 좁혀 2^32까지 줄인 다음 md5로 확정한다.
#dreamhack#ctf#crypto+5
2026-07-07
[🥈 Silver 2] nonce는 뚫지 않고, 유출은 fetch를 안 쓴다 — DreamHack CSP Bypass 풀이
blog

[🥈 Silver 2] nonce는 뚫지 않고, 유출은 fetch를 안 쓴다 — DreamHack CSP Bypass 풀이

script-src 'self' 'nonce-X'가 걸린 반사형 XSS. 인라인 스크립트는 nonce가 없어 콘솔에서 바로 막히지만, /vuln 자신이 입력을 그대로 돌려주는 걸 이용해 <script src="/vuln?param=...">로 스스로를 "동일 출처 스크립트"로 위장시키면 nonce 없이 실행된다. 유출도 fetch/img가 아니라 top-level navigation으로 — CSP가 애초에 막지 않는 경로다. 목적지는 외부 서버가 아니라 같은 앱의 전역 메모장.
#dreamhack#ctf#web+5
2026-07-07
[🥉 Bronze 2] 비밀번호 대신 배열 하나 — DreamHack [wargame.kr] strcmp 풀이
blog

[🥉 Bronze 2] 비밀번호 대신 배열 하나 — DreamHack [wargame.kr] strcmp 풀이

매 요청마다 rand()로 다시 뽑는 비밀번호를 strcmp()로 비교한다. sleep(1)까지 붙여 브루트포스를 차단했지만, 애초에 값을 맞힐 필요가 없다. PHP의 strcmp()에 배열을 넘기면 TypeError 대신 NULL을 반환하고, NULL == 0은 PHP 느슨한 비교에서 참이 된다. password 대신 password[]를 보내는 것만으로 인증을 통째로 우회한다.
#dreamhack#ctf#web+5
2026-07-07
[🥈 Silver 4] 암호문 배열을 걷어내니 로직은 열 줄도 안 됐다 — DreamHack Secure Mail 풀이
blog

[🥈 Silver 4] 암호문 배열을 걷어내니 로직은 열 줄도 안 됐다 — DreamHack Secure Mail 풀이

1.1MB짜리 난독화된 JS라 겁먹었지만, 진짜 로직은 223KB짜리 암호문 배열을 걷어내면 열 줄이 안 됐다. 생년월일 후보의 MD5를 키/IV로 쓰는 AES-128-CBC로 첨부 메일을 복호화하는 구조라, 원본 코드를 그대로 브루트포스하면 한 번에 2.3초씩 걸려 하루가 넘게 걸린다. 알고리즘만 뽑아 Node 네이티브 AES로 다시 짜서 3만 5천 개 생년월일을 45초에 끝냈다.
#dreamhack#ctf#reversing+5
2026-07-07
[🥉 Bronze 3] 확장자 블랙리스트가 빠뜨린 파일명 — DreamHack Apache htaccess 풀이
blog

[🥉 Bronze 3] 확장자 블랙리스트가 빠뜨린 파일명 — DreamHack Apache htaccess 풀이

업로드 필터는 php/php3/php4/php5/pht/phtml 확장자만 막는다. .htaccess라는 "확장자 없는" 파일명은 블랙리스트에 걸리지 않고, AllowOverride All인 서버는 업로드 디렉토리에 떨어진 그 .htaccess를 그대로 적용한다. AddType 한 줄로 .jpg를 PHP로 만들어 웹쉘을 올리고, 실행 전용 flag 바이너리를 그 웹쉘로 실행시켜 flag를 받는다.
#dreamhack#ctf#web+5
2026-07-07
[🥉 Bronze 2] 대문자 GUEST로 guest 필터 피하기 — DreamHack [wargame.kr] login filtering 풀이
blog

[🥉 Bronze 2] 대문자 GUEST로 guest 필터 피하기 — DreamHack [wargame.kr] login filtering 풀이

guest/blueh4g 계정은 PHP 문자열 비교로 블랙리스트에 걸려 있다. mysqli_real_escape_string이 따옴표를 다 막아 SQL Injection은 안 되지만, MySQL 기본 콜레이션은 문자열을 대소문자 구분 없이 비교한다. id=GUEST(대문자)로 보내면 DB 조회는 guest 행 그대로 매치하면서, PHP의 대소문자 구분 비교는 통과해 블랙리스트를 피해간다.
#dreamhack#ctf#web+5
2026-07-06
[🥈 Silver 4] 5번 제한을 100번으로 — DreamHack login-1 풀이
blog

[🥈 Silver 4] 5번 제한을 100번으로 — DreamHack login-1 풀이

회원가입은 항상 guest 등급만 만든다. /user/idx의 IDOR로 관리자 계정(Apple, level=1)을 먼저 찾아내고, 비밀번호 재설정의 2자리 백업코드는 5회 오답이면 잠기지만 그 카운트 확인과 증가 사이에 TOCTOU 레이스가 있다. 100개 값을 동시에 쏘면 잠기기 전에 정답이 섞여 나간다.
#dreamhack#ctf#web+5
2026-07-06
[🥉 Bronze 3] cat 대신 실행 — DreamHack File Vulnerability Advanced 풀이
blog

[🥉 Bronze 3] cat 대신 실행 — DreamHack File Vulnerability Advanced 풀이

경로검증 없는 /file 엔드포인트로 path traversal, /admin의 API_KEY는 Dockerfile 더미값이라 무의미해 보이지만 /proc/self/environ을 읽으면 런타임 실제 키가 그대로 나온다. 그 키로 연 /admin RCE로 flag를 찾아도 cat은 500만 뜬다 — flag가 ---x--x--x(실행 전용) ELF라 읽지 말고 실행해야 한다.
#dreamhack#ctf#web+5
2026-07-06
[🌱 새싹] cmp 명령어 하나가 곧 플래그 — DreamHack Simple Crack Me 풀이
blog

[🌱 새싹] cmp 명령어 하나가 곧 플래그 — DreamHack Simple Crack Me 풀이

정적 링크·strip된 ELF 한 개. scanf로 정수 하나를 받아 상수와 비교하는 게 로직의 전부다. objdump로 main을 까면 cmp eax,0x13371337 한 줄이 곧바로 나온다 — 그 16진수를 10진수로 바꿔 DH{}로 감싸면 플래그. gdb로 그 비교가 실행 시점에 실제로 어떻게 일어나는지까지 확인했다.
#dreamhack#ctf#reversing+4
2026-07-06
[🥉 Bronze 2] 1초 안에 덧셈 50번 — DreamHack addition-quiz 풀이
blog

[🥉 Bronze 2] 1초 안에 덧셈 50번 — DreamHack addition-quiz 풀이

서버가 alarm(1)로 1초마다 덧셈 문제를 내고 정답을 요구한다. 난수는 srand(time(NULL))이지만 예측할 필요가 없다 — 문제 자체(num1, num2)를 그대로 평문으로 출력해 주기 때문이다. 필요한 건 PRNG 역산이 아니라 recv-계산-send를 50번 반복할 스크립트뿐이다. 로컬 바이너리로 직접 재보면 50라운드 전체가 0.01초 안에 끝나 — 사람에게 허락된 50초의 5000분의 1이다.
#dreamhack#ctf#misc+4
2026-07-06
[🥈 Silver 4] 72바이트로 canary 넘어 리크, free_hook 하이재킹으로 쉘 — DreamHack fho 풀이
blog

[🥈 Silver 4] 72바이트로 canary 넘어 리크, free_hook 하이재킹으로 쉘 — DreamHack fho 풀이

read()로 정확히 72바이트만 보내 canary·saved rbp를 non-null로 덮되 return address는 건드리지 않으면, 뒤이은 printf("%s", buf)가 retaddr의 첫 null 바이트에서 멈추며 libc 주소 일부가 그대로 새어나온다. 여기에 문제가 기본 제공하는 임의주소 write/free 프리미티브를 얹어 __free_hook을 system으로 덮고 free("/bin/sh")를 부르면 그대로 쉘이 뜬다.
#dreamhack#ctf#pwnable+5
2026-07-06
[🥉 Bronze 1] 검증식을 브라우저 대신 내가 계산하기 — DreamHack funjs 풀이
blog

[🥉 Bronze 1] 검증식을 브라우저 대신 내가 계산하기 — DreamHack funjs 풀이

input 값을 검사하는 JS가 난독화돼 있지만, 실제로 가려진 건 charCodeAt·length 같은 메서드 이름뿐이다. 정답을 만드는 두 숫자 배열과 사칙연산 사이클은 평문 그대로 배달되므로, 브라우저가 할 계산을 파이썬으로 그대로 옮겨 실행하면 그게 곧 플래그다.
#dreamhack#ctf#web+5
2026-07-06
[🥈 Silver 4] free() 이전에 이미 끝난 취약점 — DreamHack hook 풀이
blog

[🥈 Silver 4] free() 이전에 이미 끝난 취약점 — DreamHack hook 풀이

malloc으로 받은 청크의 첫 16바이트를 그대로 주소·값으로 써버리는 한 줄이 문제의 전부다. free()가 두 번 불리지만 실제로는 그 이전 write-what-where 한 방으로 __free_hook을 one_gadget으로 덮고, 첫 free() 호출만으로 셸이 뜬다. double free도, fastbin dup도 필요 없다.
#dreamhack#ctf#pwnable+5
2026-07-06
[🌱 새싹] strncmp 는 앞 8바이트만 본다 — DreamHack cmd_center 풀이
blog

[🌱 새싹] strncmp 는 앞 8바이트만 본다 — DreamHack cmd_center 풀이

"ifconfig" 로 초기화된 명령 버퍼를 그대로 system() 에 넘기는 바이너리. 바로 옆 24바이트 지역 변수에 read 로 100바이트를 받아주는 탓에, 그 버퍼를 넘쳐서 명령 문자열 뒷부분에 세미콜론으로 원하는 명령을 이어붙일 수 있다. strncmp 가 앞 8글자("ifconfig")만 검사한다는 게 이 문제의 전부다.
#dreamhack#ctf#pwn+5
2026-07-06
[🥉 Bronze 4] 프로그램이 직접 알려주는 win() 주소 — DreamHack baby-bof 풀이
blog

[🥉 Bronze 4] 프로그램이 직접 알려주는 win() 주소 — DreamHack baby-bof 풀이

printf가 친절하게 win()의 주소를 그대로 출력해주고, 뒤이은 "값을 몇 번 쓸지" 입력은 스택 버퍼 크기와 아무 관계 없이 그 횟수만큼 8바이트씩 이어 쓴다. 리크된 주소를 그 값으로, 쓰기 횟수를 4로 주면 리턴 주소가 win()으로 바뀐다.
#dreamhack#ctf#pwnable+4
2026-07-05
[🥉 Bronze 4] 26가지뿐이라 그냥 다 세본다 — DreamHack Basic_Crypto1 풀이
blog

[🥉 Bronze 4] 26가지뿐이라 그냥 다 세본다 — DreamHack Basic_Crypto1 풀이

텍스트 파일 하나에 담긴 Caesar cipher. shift가 26가지뿐이라 굳이 머리 쓸 것 없이 전수조사(brute force)로 풀고, 파이썬 스크립트와 CyberChef 두 가지 방법으로 서로 교차검증했다. 사람이 눈으로 읽지 않고도 정답을 가려낼 수 있도록, 영어 알파벳 빈도와 카이제곱 통계로 자동 판별하는 방법도 추가로 확인했다.
#dreamhack#ctf#crypto+2
2026-07-05
[🌱 Sprout] 뒤집고, 뒤집고, XOR 한 번 — DreamHack simple-operation 풀이
blog

[🌱 Sprout] 뒤집고, 뒤집고, XOR 한 번 — DreamHack simple-operation 풀이

난수를 받아 XOR 하고, 8자리 hex 문자열로 만든 다음 뒤집어서 상수와 비교하는 아주 짧은 체크 루틴. 서버가 알려주는 난수 하나만 있으면 그 변환을 그대로 거꾸로 밟아 정답을 계산할 수 있다.
#dreamhack#ctf#reversing+2
2026-07-05
[🥈 Silver 3] 공백도 OR도 admin도 못 쓰는데 — 블랙리스트 WAF 뚫은 블라인드 SQLi — DreamHack sql injection bypass WAF 풀이
blog

[🥈 Silver 3] 공백도 OR도 admin도 못 쓰는데 — 블랙리스트 WAF 뚫은 블라인드 SQLi — DreamHack sql injection bypass WAF 풀이

union/select/from/and/or/admin/공백/*// 를 부분 문자열로 막는 블랙리스트 WAF 앞에서, MySQL의 ||/&&와 공백 없는 # 주석으로 문법 자체를 바꿔 우회한 기록이다. 화면엔 uid 컬럼만 반사되는 구조라 admin의 비밀번호(FLAG)는 boolean-blind로 한 글자씩 꺼내야 했다.
#dreamhack#ctf#web+4
2026-07-05
[🥈 Silver 4] 이미지 태그 하나면 충분했다 — DreamHack CSRF Advanced 풀이
blog

[🥈 Silver 4] 이미지 태그 하나면 충분했다 — DreamHack CSRF Advanced 풀이

reflected 페이지의 XSS 필터가 frame/script/on 세 단어를 '*'로 지우지만, 정작 CSRF에 필요한 건 <img src=...> 하나뿐이다. 게다가 비밀번호 변경 API의 CSRF 토큰이 md5(username+접속IP)라서, 봇이 항상 127.0.0.1로 접속한다는 사실만으로 토큰을 미리 계산해버릴 수 있었다.
#dreamhack#ctf#web+4
2026-07-05
[🥈 Silver 4] 6바이트만 덮어도 충분하다 — DreamHack oneshot 풀이
blog

[🥈 Silver 4] 6바이트만 덮어도 충분하다 — DreamHack oneshot 풀이

16바이트 버퍼에 46바이트를 읽어들이는 전형적인 스택 오버플로우. printf가 무심코 찍어준 stdout 포인터가 libc 주소라는 걸 이용해 베이스를 구하고, 남은 return address 6바이트만 one_gadget으로 덮어 셸을 딴다. rax 제약도 main이 알아서 맞춰준다.
#dreamhack#ctf#pwnable+4
2026-07-05
[🥉 Bronze 4] 왼쪽으로 돌린 비트를 오른쪽으로 되돌리기 — DreamHack rev-basic-7 풀이
blog

[🥉 Bronze 4] 왼쪽으로 돌린 비트를 오른쪽으로 되돌리기 — DreamHack rev-basic-7 풀이

입력 바이트를 (i mod 8)만큼 왼쪽으로 회전시키고 i와 XOR한 값을 31바이트 고정 테이블과 비교하는 x86-64 PE. 회전은 반대 방향으로 같은 양만큼 돌리면 정확히 원상복구되는 연산이라, 검증식을 그대로 뒤에서부터 읽어 ROR로 되돌렸다. 디스어셈블로 검증 로직을 읽고, 표를 바이너리에서 직접 추출해 역산하고, wine으로 Correct를 확인한 과정.
#dreamhack#ctf#reversing+7
2026-07-05
[🥉 Bronze 4] sprintf가 제가 쓴 글자를 되읽는다 — DreamHack basic_exploitation_003 풀이
blog

[🥉 Bronze 4] sprintf가 제가 쓴 글자를 되읽는다 — DreamHack basic_exploitation_003 풀이

sprintf(stack_buf, heap_buf)에서 heap_buf가 그대로 포맷 문자열이 되는 취약점. stack_buf가 va_arg 스캔 영역과 겹쳐서 %k$ 인자가 "우리가 방금 그 자리에 쓴 값"을 되읽는 자기참조 구조를 실험으로 확인하고, printf@GOT 하위 2바이트만 %hhn으로 덮어 get_shell()로 리다이렉트한다.
#dreamhack#ctf#pwn+5
2026-07-04
[🥈 Silver 3] ASCII()가 거짓말을 하는 블라인드 SQLi — DreamHack blind sql injection advanced 풀이
blog

[🥈 Silver 3] ASCII()가 거짓말을 하는 블라인드 SQLi — DreamHack blind sql injection advanced 풀이

uid 파라미터가 SQL에 그대로 삽입되는 boolean blind SQLi를 자동화하다가, 한글이 섞인 플래그 때문에 ASCII() 이진탐색이 끝없이 참으로 나오는 현상에 부딪혔다. MySQL의 ASCII()와 ORD()가 멀티바이트 문자를 다루는 방식 차이를 파고들어 우회한 과정을 정리한다.
#dreamhack#ctf#web+4
2026-07-04
[🥉 Bronze 2] 스택 버퍼 오버플로우 2단계 ret2libc — DreamHack basic_rop_x86 풀이
blog

[🥉 Bronze 2] 스택 버퍼 오버플로우 2단계 ret2libc — DreamHack basic_rop_x86 풀이

캐너리도 PIE도 없는 32비트 바이너리에서 read()의 고전적인 스택 오버플로우를 ROP로 두 번 나눠 공략한다. write@plt로 write() 자체의 GOT 주소를 새서 libc 베이스를 계산하고, main으로 되돌아가 system("/bin/sh")를 호출한다.
#dreamhack#ctf#pwn+4
2026-07-04
[🥉 Bronze 4] 따옴표조차 필요 없던 커맨드 인젝션 — DreamHack command-injection-chatgpt 풀이
blog

[🥉 Bronze 4] 따옴표조차 필요 없던 커맨드 인젝션 — DreamHack command-injection-chatgpt 풀이

ping 테스터의 host 입력값이 아무런 감싸기(따옴표)도 없이 f'ping -c 3 {host}' 문자열로 조립돼 /bin/sh -c 로 그대로 실행된다. 세미콜론 하나만 붙여 cat flag.py 를 이어 붙이면 ping 결과 자리에 플래그가 그대로 출력된다.
#dreamhack#ctf#web+4
2026-07-03
[🥉 Bronze 4] 곱셈 치환을 모듈러 역원으로 되돌리기 — DreamHack rev-basic-8 풀이
blog

[🥉 Bronze 4] 곱셈 치환을 모듈러 역원으로 되돌리기 — DreamHack rev-basic-8 풀이

입력 각 바이트에 0xfb를 곱하고 하위 1바이트만 남긴 값을 21바이트 고정 테이블과 비교하는 x86-64 PE. 0xfb가 mod 256에서 홀수라 곱셈의 역원이 존재한다는 점을 이용해 검증 테이블을 그대로 역산했다. 마지막 21번째 비교가 사실은 문자열 종결 NUL 검증이라는 것도 함께 정리.
#dreamhack#ctf#reversing+4
2026-07-03
[🥉 Bronze 2] 카나리 leak + GOT leak로 ret2main, 그리고 ret2system — DreamHack rop 풀이
blog

[🥉 Bronze 2] 카나리 leak + GOT leak로 ret2main, 그리고 ret2system — DreamHack rop 풀이

스택 카나리에 NX까지 켜진 클래식 ROP 문제. 입력 기회는 딱 두 번뿐이라 셸코드도, 두 번째 페이로드도 못 넣는다. 카나리를 leak한 뒤 첫 ROP 체인으로 GOT에서 libc 주소를 새고, 반환 주소를 main() 자신으로 되돌려 "세 번째 입력"을 만들어낸 다음 system("/bin/sh")로 마무리한다.
#dreamhack#ctf#pwn+7
2026-07-03
[🥉 Bronze 2] pop rdi 가젯이 없을 때 — DreamHack basic_rop_x64 ret2csu 풀이
blog

[🥉 Bronze 2] pop rdi 가젯이 없을 때 — DreamHack basic_rop_x64 ret2csu 풀이

canary 없는 스택 BOF에 NX만 켜진 64비트 바이너리. 명시적인 pop rdi;ret 가젯이 없어서 __libc_csu_init 의 레지스터 세팅 루틴(ret2csu)으로 write(1, &GOT[read], 8)을 호출해 libc를 leak하고, "pop r15" 명령 한가운데 숨어 있는 pop rdi;ret로 system("/bin/sh")까지 잇는다.
#dreamhack#ctf#pwn+6
2026-07-02
[🥈 Silver 3] 응답엔 결과가 없어도 에러엔 다 있다 — DreamHack error based sql injection 풀이
blog

[🥈 Silver 3] 응답엔 결과가 없어도 에러엔 다 있다 — DreamHack error based sql injection 풀이

uid 값을 그대로 문자열 포매팅해 쿼리를 만드는 Flask + MariaDB 앱. 성공 응답은 항상 같은 쿼리 템플릿만 echo해 UNION이나 boolean 기반으로는 아무것도 구분할 수 없지만, 예외를 str(e)로 그대로 돌려주는 탓에 extractvalue()의 XPATH syntax error에 서브쿼리 결과를 실어 admin 비밀번호(플래그)를 통째로 읽어낸다.
#dreamhack#ctf#web+4
2026-07-01
[🥉 Bronze 1] flag는 못 읽어도 소스는 새어나간다 — DreamHack php-1 풀이
blog

[🥉 Bronze 1] flag는 못 읽어도 소스는 새어나간다 — DreamHack php-1 풀이

PHP Back Office. view.php 는 파일 파라미터에 "flag" 문자열과 콜론을 막아 php://filter 우회까지 봉쇄했지만, 정작 include 를 직접 호출하는 index.php 의 page 파라미터엔 같은 필터가 없다. 확장자 자동 첨부를 거꾸로 이용해 php://filter/convert.base64-encode 로 flag.php 소스를 실행 대신 텍스트로 읽어낸다.
#dreamhack#ctf#web+4
2026-07-01
[🥉 Bronze 4] AES S-box를 거꾸로 — DreamHack rev-basic-6 풀이
blog

[🥉 Bronze 4] AES S-box를 거꾸로 — DreamHack rev-basic-6 풀이

입력을 한 글자씩 256바이트 치환표로 바꿔 고정된 18바이트와 비교하는 x86-64 PE. 그 치환표가 AES S-box라는 걸 알아채면 끝난다. S-box를 한 번 뒤집어 기대값을 역치환하면 입력이 그대로 나온다. 디스어셈블로 검증 로직을 읽고, 표를 추출해 역산하고, wine으로 Correct를 확인한 과정.
#dreamhack#ctf#reversing+5
2026-07-01
[🥉 Bronze 4] 정답을 흘리는 NULL 종단 — DreamHack rev-basic-5 풀이
blog

[🥉 Bronze 4] 정답을 흘리는 NULL 종단 — DreamHack rev-basic-5 풀이

입력의 인접한 두 바이트를 더해 .data 테이블과 비교하는 x86-64 PE. 식만 보면 미지수가 하나 남는 부정방정식이지만, 입력 버퍼가 0으로 초기화돼 문자열이 NULL로 끝난다는 점과 테이블 마지막 값이 0이라는 점이 오른쪽 끝을 고정한다. 거기서 왼쪽으로 도미노처럼 역산하면 입력이 그대로 나온다.
#dreamhack#ctf#reversing+4
2026-07-01
[🥉 Bronze 3] raw socket 으로 만든 SSRF — localhost 전용 /admin 우회 — DreamHack proxy-1 풀이
blog

[🥉 Bronze 3] raw socket 으로 만든 SSRF — localhost 전용 /admin 우회 — DreamHack proxy-1 풀이

임의 host:port 로 raw 바이트를 보내고 응답을 돌려주는 /socket 이 그대로 SSRF 발판이 된다. flag 를 주는 /admin 은 remote_addr 가 127.0.0.1 일 때만 동작하는데, /socket 으로 서버 자신의 8000 포트에 생 HTTP 요청을 흘려보내면 이 검사를 통과한다. 요청에 필요한 헤더·쿠키·폼까지 직접 적어 보내 flag 를 회수했다.
#dreamhack#ctf#web+5
2026-06-30
[🥉 Bronze 1] 카나리 흘리고 system 으로 되돌아가기 — DreamHack Return to Library 풀이
blog

[🥉 Bronze 1] 카나리 흘리고 system 으로 되돌아가기 — DreamHack Return to Library 풀이

NX 가 켜져 스택 셸코드를 못 쓰는 BOF 문제. 첫 read 뒤 printf("%s") 가 카나리 LSB(\x00) 만 덮으면 상위 7바이트를 흘려준다. 그걸로 카나리를 복원하고, 두 번째 read 오버플로우로 pop rdi → "/bin/sh" → system@plt 로 이어지는 ret2plt 체인을 올려 셸을 띄운다. 바이너리가 처음에 system 을 한 번 호출해 줘서 PLT 가 이미 채워져 있는 게 포인트.
#dreamhack#ctf#pwn+6
2026-06-30
[🥉 Bronze 2] GET만 열어둔 Flask 라우트를 HEAD로 뚫기 — DreamHack blind-command 풀이
blog

[🥉 Bronze 2] GET만 열어둔 Flask 라우트를 HEAD로 뚫기 — DreamHack blind-command 풀이

Flask 라우트에 methods=['GET']만 걸어도 HEAD와 OPTIONS는 자동으로 따라붙는다. HEAD 요청이면 request.method가 'HEAD'가 되어 else 분기의 os.system(cmd)이 실행되지만, HEAD 응답엔 본문이 없어 출력이 보이지 않는다. sleep 시간차로 flag를 한 글자씩 빼냈다.
#dreamhack#ctf#web+4
2026-06-28
[🥈 Silver 3] 404 페이지에 식을 넣으면 답을 한다 — DreamHack simple-ssti 풀이
blog

[🥈 Silver 3] 404 페이지에 식을 넣으면 답을 한다 — DreamHack simple-ssti 풀이

Flask 404 핸들러가 사용자 경로(request.path)를 템플릿 문자열에 그대로 박은 뒤 render_template_string 으로 렌더한다. 없는 경로에 Jinja2 식을 실으면 서버가 평가하는 SSTI 가 터지고, FLAG 가 app.secret_key 로 들어가 있어 config 한 줄로 그대로 새어 나온다.
#dreamhack#ctf#web+5
2026-06-28
[🥉 Bronze 2] 지운 줄 알았던 flag — DreamHack blue-whale 풀이
blog

[🥉 Bronze 2] 지운 줄 알았던 flag — DreamHack blue-whale 풀이

Dockerfile이 flag 내용을 '파일 이름'으로 touch 한 뒤 rm * 로 지운다. 컨테이너 안에는 아무것도 안 남지만, 도커 이미지는 레이어(tar)의 더미라 상위 레이어의 삭제는 하위 레이어를 못 지운다. Docker Hub의 공개 이미지를 받아 docker save로 레이어를 까면 touch 단계 레이어에 flag 파일명이 그대로 박혀 있다.
#dreamhack#ctf#misc+6
2026-06-27
[🥉 Bronze 2] OOB read 로 카나리 흘려보고 BOF 로 셸 — DreamHack ssp_001 풀이
blog

[🥉 Bronze 2] OOB read 로 카나리 흘려보고 BOF 로 셸 — DreamHack ssp_001 풀이

스택 카나리가 켜진 32비트 BOF 문제. (P)rint 메뉴의 box[idx] 가 인덱스 검사를 안 해 OOB read 가 되고, box 기준 +0x80 위치에 있는 카나리 4바이트를 그대로 읽어올 수 있다. 카나리를 복원한 뒤 (E)xit 메뉴의 read(name, name_len) 길이 무제한 오버플로우로 카나리를 그대로 채우고 반환 주소를 get_shell 로 덮어 셸을 잡는다.
#dreamhack#ctf#pwn+6
2026-06-27
[🥉 Bronze 2] 칸 하나짜리 로그인 폼으로 admin 행만 콕 — DreamHack simple_sqli_chatgpt 풀이
blog

[🥉 Bronze 2] 칸 하나짜리 로그인 폼으로 admin 행만 콕 — DreamHack simple_sqli_chatgpt 풀이

로그인 폼에 입력칸이 userlevel 하나뿐인데, 그 값이 따옴표째 쿼리에 박힌다. guest와 admin 둘 다 userlevel이 0이라 흔한 or 1=1은 첫 행 guest를 데려온다. userid를 직접 지정해 admin 행만 남긴 과정을 정리했다.
#dreamhack#ctf#web+5
2026-06-27
[🥉 Bronze 4] 한 값이 74보다 작고 동시에 크다 — DreamHack php7cmp4re 풀이
blog

[🥉 Bronze 4] 한 값이 74보다 작고 동시에 크다 — DreamHack php7cmp4re 풀이

PHP 7의 비교 연산자는 피연산자 타입에 따라 규칙이 바뀐다. 정수와 비교하면 문자열을 숫자로 캐스팅하고, 문자열끼리 비교하면 바이트 단위 strcmp를 쓴다. 이 비대칭을 이용하면 "7g" 한 값이 74보다 작으면서 동시에 "74"보다 크게 만들 수 있다. input1도 같은 원리로 0x39와 0x41 사이 문자를 끼워 통과시킨다.
#dreamhack#ctf#web+4
2026-06-26
[🥉 Bronze 3] 카나리 흘려보고 스택에 셸코드 심기 — DreamHack Return to Shellcode 풀이
blog

[🥉 Bronze 3] 카나리 흘려보고 스택에 셸코드 심기 — DreamHack Return to Shellcode 풀이

NX 가 꺼져(스택 RWX) 있지만 스택 카나리가 켜진 BOF 문제. read 뒤의 printf("%s") 가 카나리의 LSB(\x00) 를 덮으면 상위 7바이트를 흘려주고, 그걸로 카나리를 복원한다. 그다음 gets() 무제한 오버플로우로 스택에 셸코드를 올리고 카나리를 그대로 채운 뒤 반환 주소를 buf 로 돌려 ret2shellcode 로 셸을 띄운다.
#dreamhack#ctf#pwn+6
2026-06-26
[🥉 Bronze 2] 대소문자 한 끗으로 뚫는 XSS 필터 — DreamHack XSS Filtering Bypass 풀이
blog

[🥉 Bronze 2] 대소문자 한 끗으로 뚫는 XSS 필터 — DreamHack XSS Filtering Bypass 풀이

script·on·javascript: 를 지우는 필터가 있는데도, 검사는 소문자로 하고 치환은 원본 그대로 한다는 한 줄 차이 때문에 <sCrIpt> 가 그대로 살아남는다. 봇이 들고 방문하는 flag 쿠키를 동기 XHR로 /memo에 흘려 회수한 과정을 정리했다. location.href 비동기 전송이 driver.quit 레이스에 걸려 실패했던 삽질까지 담았다.
#dreamhack#ctf#web+6
2026-06-26
[🥈 Silver 4] 검은 가림막을 ret 한 줄로 걷어내다 — DreamHack patch 풀이
blog

[🥈 Silver 4] 검은 가림막을 ret 한 줄로 걷어내다 — DreamHack patch 풀이

GDI+ 라인 드로잉으로 flag를 그리는 Windows GUI 프로그램. flag 글자를 검정으로 그리기 전에, 같은 검정으로 두꺼운 선을 겹쳐 그려 가운데를 덮는 "가림막"을 먼저 깐다. 검정 글자가 검정 가림막 위에 얹히니 안 보일 뿐이다. 가림막을 그리는 함수의 첫 바이트를 ret(0xC3)로 패치해 가림막을 통째로 없애면 flag가 흰 배경 위에 그대로 드러난다.
#dreamhack#ctf#reversing+4
2026-06-25
[🥉 Bronze 3] flag는 서비스가 아니라 이미지 안에 있었다 — DreamHack Exercise: Docker 풀이
blog

[🥉 Bronze 3] flag는 서비스가 아니라 이미지 안에 있었다 — DreamHack Exercise: Docker 풀이

Dockerfile 하나와 socat으로 노출되는 바이너리가 주어지는 Docker 실습 문제. 서비스에 접속하면 "Hello Beginners!"만 나오고 바이너리는 flag를 출력하지 않는다. 핵심은 Dockerfile이 flag 파일을 이미지 안(/home/chall/flag)으로 ADD 한다는 것 — 같은 Dockerfile로 이미지를 빌드하고 컨테이너를 실행해 그 안의 flag를 그대로 읽는다.
#dreamhack#ctf#misc+4
2026-06-25
[🥉 Bronze 4] 인코딩 체인을 역순으로 되감기 — DreamHack tools-cyberchef 풀이
blog

[🥉 Bronze 4] 인코딩 체인을 역순으로 되감기 — DreamHack tools-cyberchef 풀이

index.html 한 장에 암호문과 "Rail Fence → Base64 → ROT13" 라는 인코딩 순서가 적혀 있다. 인코딩을 거꾸로(ROT13 → From Base64 → Rail Fence Decode) 되감으면 플래그가 나온다. 이름값을 하는 문제답게 CyberChef 레시피로, 그리고 파이썬으로 복원해 라운드트립까지 검증한다.
#dreamhack#ctf#misc+6
2026-06-25
[🌱 새싹] admin 세션 ID가 단 1바이트였다 — DreamHack session 풀이
blog

[🌱 새싹] admin 세션 ID가 단 1바이트였다 — DreamHack session 풀이

로그인 세션을 쿠키 하나로 식별하는 Flask 앱. 일반 사용자 세션은 4바이트 난수로 만들지만, 서버가 시작할 때 미리 깔아 두는 admin 세션은 os.urandom(1) — 단 1바이트(00~ff, 256가지)로 만든다. sessionid 쿠키를 256번 갈아 끼우면 admin 세션을 그대로 주워 flag를 읽는다.
#dreamhack#ctf#web+5
2026-06-25
[🌱 Sprout] 기본 자격증명으로 설정값 읽기 — DreamHack web-misconf-1 풀이
blog

[🌱 Sprout] 기본 자격증명으로 설정값 읽기 — DreamHack web-misconf-1 풀이

Grafana 6.6.2의 admin 비밀번호가 초기값 admin 그대로다. 기본 자격증명으로 로그인한 뒤 /api/admin/settings 가 실행 중 설정을 통째로 돌려주는데, 민감 키만 가려지고 평범한 키는 평문이라 auth.anonymous.org_name 에 숨겨둔 플래그가 그대로 노출된다.
#dreamhack#ctf#web+4
2026-06-25
[🥉 Bronze 4] 반환 주소를 get_shell 로 덮는다 — DreamHack Return Address Overwrite 풀이
blog

[🥉 Bronze 4] 반환 주소를 get_shell 로 덮는다 — DreamHack Return Address Overwrite 풀이

scanf("%s") 로 스택 버퍼를 넘쳐 반환 주소를 덮는, pwnable 입문의 정석. NX 가 켜져 있어 스택 셸코드는 못 올리지만 바이너리 안에 execve("/bin/sh") 를 부르는 get_shell 함수가 이미 있다. 반환 주소를 그 함수 주소로 덮어 흐름을 가져오는 코드 재사용(ret2win) 기법으로 셸을 띄운다.
#dreamhack#ctf#pwn+5
2026-06-25
[🥉 Bronze 2] scanf 가 셸코드를 잘라먹는다 — DreamHack basic_exploitation_000 풀이
blog

[🥉 Bronze 2] scanf 가 셸코드를 잘라먹는다 — DreamHack basic_exploitation_000 풀이

buf 주소를 친절히 누출해 주고 scanf 로 스택을 넘치게 하는 전형적인 스택 셸코드 문제. 그런데 교과서 execve 셸코드를 그대로 쓰면 동작하지 않는다. scanf("%s") 가 셸코드 안의 0x0b(SYS_execve) 를 공백으로 보고 거기서 잘라먹기 때문. 0x0b 바이트 없이 11을 만들어 우회하고, 누출된 buf 주소로 점프해 셸을 띄운다.
#dreamhack#ctf#pwn+5
2026-06-25
[🥉 Bronze 4] gets() 한 줄로 리턴 주소를 read_flag로 — DreamHack basic_exploitation_001 풀이
blog

[🥉 Bronze 4] gets() 한 줄로 리턴 주소를 read_flag로 — DreamHack basic_exploitation_001 풀이

buf[0x80]에 길이 제한 없는 gets()가 입력을 받는다. 128바이트 버퍼에 saved EBP 4바이트를 더한 132바이트 뒤에 리턴 주소가 있고, 그 자리를 system("cat flag")를 부르는 read_flag() 주소로 덮으면 끝이다. 카나리도 PIE도 없어 오프셋과 주소가 그대로 고정인 교과서적 ret2win.
#dreamhack#ctf#pwnable+5
2026-06-25
[🌱 Sprout] GET·POST 요청 체이닝 — 리다이렉트 따라가며 토큰 이어 붙이기 — DreamHack simple-web-request 풀이
blog

[🌱 Sprout] GET·POST 요청 체이닝 — 리다이렉트 따라가며 토큰 이어 붙이기 — DreamHack simple-web-request 풀이

STEP1 → STEP2 → FLAG 세 단계를 정해진 파라미터로 차례로 호출해야 플래그가 나오는 요청 입문 문제다. 각 단계는 앞 단계가 발급한 난수 토큰을 들고 와야 통과하고, 그 토큰은 한 요청 흐름 안에서만 유효하다. 브라우저로 한 번, 그리고 requests.Session 으로 리다이렉트를 자동 추적하며 hidden 토큰을 이어 붙여 플래그를 받았다.
#dreamhack#ctf#web+5
2026-06-24
[🥈 Silver 2] SSRF로 내부 포트 스캔 — netloc 문자열 필터를 0.0.0.0으로 우회 — DreamHack web-ssrf 풀이
blog

[🥈 Silver 2] SSRF로 내부 포트 스캔 — netloc 문자열 필터를 0.0.0.0으로 우회 — DreamHack web-ssrf 풀이

이미지 뷰어가 입력한 URL을 서버가 대신 가져와 보여준다. 같은 프로세스 안에 flag.txt를 서빙하는 내부 SimpleHTTPRequestHandler가 1500~1800 중 한 포트에 떠 있다. 필터는 netloc에 `127.0.0.1`/`localhost` 문자열이 있는지만 보므로, 같은 loopback을 가리키는 `0.0.0.0`으로 우회하고 포트를 전수 스캔해 flag.txt를 읽었다.
#dreamhack#ctf#web+5
2026-06-24
[🌱 새싹] 화면에 흩날리는 글자를 슬라이스로 되맞추기 — DreamHack Flying Chars 풀이
blog

[🌱 새싹] 화면에 흩날리는 글자를 슬라이스로 되맞추기 — DreamHack Flying Chars 풀이

플래그 한 줄을 20조각 이미지로 잘라 10×10px 로 줄인 뒤 제각각 속도로 화면에 흘려보내는 문제다. 눈으로는 못 읽지만 조각은 그대로 서버에 있다. 파일명 숫자순으로 맞추면 깨진 문장이 나오고, HTML 의 img_files 배열(브라우저가 화면에 붙이는 순서) 그대로 이어 붙이면 플래그가 복원된다. 클라이언트에서 가리는 건 숨기는 게 아니라는 전형적인 예제.
#dreamhack#ctf#web+3
2026-06-24
[🥉 Bronze 4] execve 만 막힌 seccomp 안에서 ORW 셸코드로 flag 읽기 — DreamHack shell_basic 풀이
blog

[🥉 Bronze 4] execve 만 막힌 seccomp 안에서 ORW 셸코드로 flag 읽기 — DreamHack shell_basic 풀이

RWX 영역에 올린 셸코드를 그대로 실행해 주는데, seccomp 가 execve/execveat 만 KILL 한다. 셸은 못 따니 open-read-write 셸코드로 flag 파일을 직접 읽어 표준출력으로 흘려보낸다. 표준 경로 /home/shell_basic/flag 가 아니라 getdents64 로 디렉토리를 뒤져 진짜 이름을 찾아야 했다.
#dreamhack#ctf#pwnable+5
2026-06-23
[🥉 Bronze 4] ssh 로 서버에 들어가 flag 를 읽는다 — DreamHack Exercise: SSH 풀이
blog

[🥉 Bronze 4] ssh 로 서버에 들어가 flag 를 읽는다 — DreamHack Exercise: SSH 풀이

드림핵 미스크 탭의 SSH 연습 문제. 익스플로잇은 없고, 주어진 계정으로 원격 서버에 ssh 로 접속해 홈에 놓인 flag 파일을 읽으면 끝난다. ssh 가 무엇이고 첫 접속 때 왜 호스트 키를 확인시키는지, root 소유 파일을 어떻게 일반 계정이 읽을 수 있는지(파일 권한), 들어간 셸이 사실 restricted bash 라는 디테일까지 입문자 눈높이로 짚는다.
#dreamhack#ctf#misc+4
2026-06-23
[🥉 Bronze 4] 접속만 하면 바이너리가 플래그를 읽어 준다 — DreamHack welcome 풀이
blog

[🥉 Bronze 4] 접속만 하면 바이너리가 플래그를 읽어 준다 — DreamHack welcome 풀이

드림핵 포너블 탭의 첫 연습 문제. 익스플로잇은 없고, 서버에서 도는 welcome 바이너리가 스스로 /flag 를 열어 출력해 준다. 우리가 할 일은 nc 로 그 서비스에 붙어 출력을 받는 것뿐이다. 서버형 포너블이 어떻게 굴러가는지, 왜 바이너리를 내 컴퓨터에서 돌리면 segfault 가 나는지, 같은 일을 pwntools 로 스크립트화하면 어떻게 되는지까지 입문자 눈높이로 짚는다.
#dreamhack#ctf#pwn+4
2026-06-23
[🥉 Bronze 3] 첨부파일 안에 들어있는 첫 플래그 — DreamHack Wargame Tutorial 풀이
blog

[🥉 Bronze 3] 첨부파일 안에 들어있는 첫 플래그 — DreamHack Wargame Tutorial 풀이

드림핵이 워게임 사용법을 익히라고 만들어 둔 튜토리얼 문제. 첨부파일을 받아 압축을 풀면 flag.txt 안에 플래그가 평문으로 들어 있고, 그 값을 그대로 제출하면 끝난다. 풀이 기술은 없지만, 파일 다운로드 → 압축 해제 → 플래그 확인 → 제출이라는 워게임의 기본 흐름과 flag.txt를 읽을 때 흔히 놓치는 끝의 개행 한 바이트까지 짚어본다.
#dreamhack#ctf#misc+3
2026-06-22
[🥉 Bronze 4] PHP 정규식 3겹 뚫기 — preg_replace 겹침·알파벳 없는 비번·flag 필터 우회 RCE — DreamHack phpreg 풀이
blog

[🥉 Bronze 4] PHP 정규식 3겹 뚫기 — preg_replace 겹침·알파벳 없는 비번·flag 필터 우회 RCE — DreamHack phpreg 풀이

PHP의 preg_replace·preg_match로 만든 관문 세 개를 차례로 뚫는 문제다. 닉네임은 'nyang'을 겹치게 끼워 한 번만 지워지게 만들고, 비밀번호는 알파벳 없이 치환 패턴을 맞추고, 마지막 cmd는 'flag' 필터를 와일드카드로 우회해 RCE로 flag.txt를 읽었다.
#dreamhack#ctf#web+5
2026-06-22
[🥉 Bronze 4] echo $(...) 명령 주입 — 와일드카드로 'flag' 필터 우회 — DreamHack baby-linux 풀이
blog

[🥉 Bronze 4] echo $(...) 명령 주입 — 와일드카드로 'flag' 필터 우회 — DreamHack baby-linux 풀이

입력을 echo $(...) 안에 그대로 끼워 /bin/sh 로 실행하는 단순한 페이지. 명령 주입은 바로 되지만 cmd 문자열에 'flag' 가 들어가면 차단된다. 셸 와일드카드 f* 로 'flag' 리터럴을 피해 flag.txt 를 읽어냈다.
#dreamhack#ctf#misc+4
2026-06-22
[🥈 Silver 4] MongoDB NoSQL 인젝션 + 글자별 클래스로 BAN 우회 — DreamHack Mango 풀이
blog

[🥈 Silver 4] MongoDB NoSQL 인젝션 + 글자별 클래스로 BAN 우회 — DreamHack Mango 풀이

Express + Mongoose 로그인에서 쿼리스트링 연산자 주입이 통한다. admin·dh 문자열은 BAN으로 막혀 있지만, 정규식의 각 글자를 `[c]` 캐릭터 클래스로 감싸면 substring 검사의 인접이 끊겨 우회된다. `uid[$regex]`로 admin을 특정하고 `upw[$regex]`로 flag를 한 글자씩 blind 추출했다.
#dreamhack#ctf#web+5
2026-06-22
[🥉 Bronze 4] re.match는 끝을 보지 않는다 — 정규식 접두사만 맞춰 통과 — DreamHack ex-reg-ex 풀이
blog

[🥉 Bronze 4] re.match는 끝을 보지 않는다 — 정규식 접두사만 맞춰 통과 — DreamHack ex-reg-ex 풀이

이메일 비슷한 정규식을 만족하면 FLAG를 주는 문제다. 핵심은 검사에 쓴 `re.match`가 문자열 시작만 보고 끝(`$`)을 고정하지 않는다는 점. 진짜 이메일을 넣을 필요 없이 패턴 조각을 하나씩 채운 접두사 `draaaaae1am@abc.com` 한 줄로 통과했다.
#dreamhack#ctf#web+4
2026-06-22
[🥉 Bronze 4] 검증 없는 파일 업로드 — PHP 웹셸 한 줄로 RCE — DreamHack image-storage 풀이
blog

[🥉 Bronze 4] 검증 없는 파일 업로드 — PHP 웹셸 한 줄로 RCE — DreamHack image-storage 풀이

이미지 공유 사이트인데 업로드 파일의 확장자도 MIME도 검사하지 않는다. `<?php system($_GET['cmd']); ?>` 한 줄짜리 웹셸을 shell.php로 올리면 업로드 디렉토리에 그대로 저장되고, 그 URL을 직접 열면 PHP가 실행돼 RCE가 된다. www-data 셸로 루트의 flag.txt를 읽었다.
#dreamhack#ctf#web+4
2026-06-22
[🌱 새싹] 호박을 만 번 깎으면 떨어지는 플래그 — DreamHack Carve Party 풀이
blog

[🌱 새싹] 호박을 만 번 깎으면 떨어지는 플래그 — DreamHack Carve Party 풀이

서버도 백엔드도 없는 HTML 한 장짜리 문제. 호박을 10000번 클릭하면 canvas에 플래그가 그려지는데, 그 플래그 바이트는 클릭 100번마다 한 번씩 XOR 변환을 거친다. 키로 쓰이는 pie 변수가 함수 밖 전역이라 배치 사이에 값이 이어진다는 점만 잡으면, 손으로 만 번 누르는 대신 100배치를 그대로 시뮬레이션해서 플래그를 꺼낼 수 있다.
#dreamhack#ctf#web+4
2026-06-22
[🥉 Bronze 4] nc로 처음 잡아보는 플래그 — DreamHack Exercise: Welcome-Beginners 풀이
blog

[🥉 Bronze 4] nc로 처음 잡아보는 플래그 — DreamHack Exercise: Welcome-Beginners 풀이

서버에서 도는 프로그램이 ./flag 를 읽어 메모리에 올려두고, 입력한 문자열이 "Dreamhack" 과 정확히 같을 때만 그 플래그를 출력한다. 익스플로잇이랄 게 없고, nc 로 접속해 strcmp 게이트가 원하는 답을 한 줄 넣어주면 끝. 드림핵 워게임의 nc 접속·플래그 회수 흐름을 처음부터 짚어본다.
#dreamhack#ctf#misc+4
2026-06-21
[🥉 Bronze 3] img 한 줄로 봇을 시켜 admin 비밀번호를 바꾸기 — DreamHack csrf-2 풀이
blog

[🥉 Bronze 3] img 한 줄로 봇을 시켜 admin 비밀번호를 바꾸기 — DreamHack csrf-2 풀이

admin의 비밀번호가 곧 FLAG인데, 직접 알아낼 방법은 없다. 대신 127.0.0.1에서 admin 세션으로 도는 봇에게 /change_password를 대신 호출하게 만들면 admin 비번을 내가 정한 값으로 덮어쓸 수 있다. script·frame·on을 막는 필터는 img 태그 한 줄로 통과하고, 바뀐 비번으로 admin 로그인해 flag를 회수한 과정을 정리했다.
#dreamhack#ctf#web+6
2026-06-21
[🌱 새싹] 따옴표 하나로 셸을 가른다 — DreamHack command-injection-1 풀이
blog

[🌱 새싹] 따옴표 하나로 셸을 가른다 — DreamHack command-injection-1 풀이

ping 테스터가 입력한 host를 ping -c 3 "{host}" 문자열로 만들어 /bin/sh -c 로 실행한다. 필터가 한 줄도 없어서, 큰따옴표를 닫고 cat /app/flag.py 를 끼워 넣은 뒤 끝의 #로 닫는 따옴표를 주석 처리하면 플래그가 ping 결과 자리에 그대로 출력된다.
#dreamhack#ctf#web+4
2026-06-21
[🥉 Bronze 1] img 한 줄로 봇을 빌려 내부 전용 /admin 호출하기 — DreamHack csrf-1 풀이
blog

[🥉 Bronze 1] img 한 줄로 봇을 빌려 내부 전용 /admin 호출하기 — DreamHack csrf-1 풀이

외부에서 직접 부르면 Access Denied인 /admin/notice_flag를, 127.0.0.1에서 도는 봇의 브라우저로 대신 호출하게 만드는 전형적인 CSRF 문제. script·frame·on을 막는 XSS 필터는 img 태그 한 줄이면 그냥 통과하고, 봇이 그 이미지를 로드하며 flag를 memo에 적어준다. 그 memo를 읽어 플래그를 회수한 과정을 정리했다.
#dreamhack#ctf#web+5
2026-06-20
[🥉 Bronze 2] 따옴표 하나로 admin 행만 콕 집기 — DreamHack simple_sqli 풀이
blog

[🥉 Bronze 2] 따옴표 하나로 admin 행만 콕 집기 — DreamHack simple_sqli 풀이

로그인 쿼리에 userid가 따옴표째 그대로 박힌다. admin 행만 정확히 반환시켜야 플래그가 나오는데, 흔한 ` or 1=1`은 첫 행 guest를 데려온다. 주석으로 패스워드 조건을 지워 admin 행만 집어낸 과정을 정리했다.
#dreamhack#ctf#web+5
2026-06-20
[🌱 새싹] 필터는 업로드에만 걸려 있었다 — DreamHack file-download-1 풀이
blog

[🌱 새싹] 필터는 업로드에만 걸려 있었다 — DreamHack file-download-1 풀이

메모 저장소 Flask 앱. 업로드 경로는 파일명에 '..'가 들어가면 막지만, 읽기 경로(/read)에는 같은 검사가 빠져 있다. uploads 디렉토리를 기준으로 경로를 그대로 이어붙이는 탓에 /read?name=../flag.py 한 줄로 상위 디렉토리의 flag.py를 그대로 읽어 플래그를 가져온다.
#dreamhack#ctf#web+4
2026-06-20
[⭐⭐] nginx ACL을 \xA0 한 바이트로 — DreamHack youth-Case 풀이
blog

[⭐⭐] nginx ACL을 \xA0 한 바이트로 — DreamHack youth-Case 풀이

nginx가 막은 POST /shop을 경로 끝의 raw \xA0(NBSP) 한 바이트로 우회한다. nginx는 \xA0를 경로에 남겨 deny 규칙과 어긋나지만 Node url.parse는 그 공백을 떼어내 /shop으로 라우팅한다. leg 필터는 합자 fl로 toLowerCase/toUpperCase 비대칭을 찔러 통과한다.
#dreamhack#ctf#web+6
2026-06-08
[🌱 새싹] 바이트 단위 ROT128 복호 — DreamHack ROT128 풀이
blog

[🌱 새싹] 바이트 단위 ROT128 복호 — DreamHack ROT128 풀이

flag.png를 암호화해 encfile로 남긴 rot128.py를 분석한다. 각 바이트에 +128 mod 256을 적용하고 2자리 16진수 텍스트로 이어붙인 단순 치환이며, 128을 두 번 더하면 원래대로 돌아오는 자기역원이다. 같은 연산을 한 번 더 돌려 PNG를 복원하고 플래그를 읽는다.
#dreamhack#ctf#crypto+4
2026-06-08
[💎 Diamond 1] Math.exp가 NaN을 잊을 때 (5) — read에서 flag까지: 불가능이라던 부트스트랩을 뒤집고 라이브 서버를 뚫다 — DreamHack EXP-NaN
blog

[💎 Diamond 1] Math.exp가 NaN을 잊을 때 (5) — read에서 flag까지: 불가능이라던 부트스트랩을 뒤집고 라이브 서버를 뚫다 — DreamHack EXP-NaN

4편은 ".at() 무가드 OOB read는 확정, 그런데 write는 여전히 막혀 있고 read→write 다리는 addrof/fakeobj뿐"으로 끝났다. 5편은 그 다리를 건너 라이브 flag까지 가는 기록이다 — 그리고 솔직히 3일이 걸렸다. addrof/fakeobj 부트스트랩이 "nursery monoculture로 불가능"이라던 결론을 뒤집고(진짜 원인은 globalThis 저장이 fold를 deopt시킨 것), fake FixedDoubleArray로 첫 forward 케이지 R/W를 열고, 그게 GC 신뢰성에서 이틀을 막았다가 "오프셋 가정을 런타임 leak으로 바꾸는" 한 줄로 5/5가 됐다. 거기서 fake Float64Array의 base_pointer를 갈아끼워 data_ptr을 절대주소로 지정하는 양방향 R/W로 backward 인스턴스까지 읽고, V12 Revenge에서 쓴 imported_function_targets 덮기로 절대주소 누출 없이 execve("/bin/sh")까지. 익스는 서버 한도(2000B)에 맞춰 1999바이트로 깎았고, 로컬 10/10이 서버에선 0/12로 죽길래 진단을 보냈더니 mapArr 하나만 환경마다 달랐다(0x18d7b9 vs 0x10d7b9) — 그걸 런타임 leak으로 적응시켜 host3.dreamhack.games에서 flag를 회수했다.
#dreamhack#ctf#pwn+8
2026-06-08
[🥈 Silver 3] NoSQL 연산자 주입으로 admin 비밀번호 훔치기 — DreamHack Not-only 풀이
blog

[🥈 Silver 3] NoSQL 연산자 주입으로 admin 비밀번호 훔치기 — DreamHack Not-only 풀이

Mongoose 로그인이 req.body 를 그대로 findOne 쿼리에 넣는다. JSON 바디로 $ne 연산자를 보내 비밀번호 없이 로그인하고, /user 가 노출하는 admin 값으로 진짜 admin 유저를 찾는다. $regex blind 로 비밀번호를 한 글자씩 뽑는데, 플래그는 admin 두 명의 비밀번호에 반씩 쪼개져 있었다.
#dreamhack#ctf#web+4
2026-06-08
[🥉 Bronze 1] 금지된 역연산을 허용 모드로 재조립하다 — DreamHack Textbook-DES 풀이
blog

[🥉 Bronze 1] 금지된 역연산을 허용 모드로 재조립하다 — DreamHack Textbook-DES 풀이

3DES EDE(K1,K2,K1)로 암호화한 플래그를 주는 오라클인데, 정작 복호에 필요한 DED 모드만 막아 뒀다. E/D를 자리별로 고를 수 있는 점을 이용해 DEE·DDD·EED 세 번을 합치면 막힌 DED와 똑같은 효과가 나온다. 키를 몰라도 평문이 복원된다.
#dreamhack#ctf#crypto+4
2026-06-08
[🥉 Bronze 4] 경계 없는 배열 인덱스로 system 인자 바꿔치기 — DreamHack out_of_bound 풀이
blog

[🥉 Bronze 4] 경계 없는 배열 인덱스로 system 인자 바꿔치기 — DreamHack out_of_bound 풀이

command[idx]에 인덱스 검사가 없어 배열 밖 메모리를 포인터로 읽는다. 마침 command[19]가 우리가 채우는 전역 name 버퍼와 주소가 겹치니, name에 "/bin/sh를 가리키는 포인터"를 심으면 system("/bin/sh")가 그대로 호출된다. NX·카나리·No PIE 환경에서 셸코드도 RIP 덮어쓰기도 없이 셸을 딴다.
#dreamhack#ctf#pwnable+4
2026-06-08
[🥈 Silver 3] eval() 화이트리스트 필터를 chr()로 우회하기 — DreamHack Addition calculator 풀이
blog

[🥈 Silver 3] eval() 화이트리스트 필터를 chr()로 우회하기 — DreamHack Addition calculator 풀이

덧셈식을 받아 eval()로 계산하는 Flask 계산기. 따옴표·언더스코어·콤마가 전부 화이트리스트 밖이라 문자열 리터럴을 못 쓰고, flag·system 같은 단어는 블랙리스트로 막힌다. chr() 코드포인트를 +로 이어 "flag.txt"를 조립해 open().read()로 ./flag.txt를 읽어낸다.
#dreamhack#ctf#web+4
2026-06-08
[🌱 새싹] 한 바이트의 니블을 맞바꾸는 검증 — DreamHack rev-basic-4 풀이
blog

[🌱 새싹] 한 바이트의 니블을 맞바꾸는 검증 — DreamHack rev-basic-4 풀이

rev-basic-3이 XOR·산술을 끼웠다면 4번은 비트로 논다. 각 글자의 상위 4비트와 하위 4비트를 맞바꾼(니블 스왑) 값이 .data 테이블과 같아야 통과한다. 니블 스왑은 두 번 하면 제자리라 테이블을 한 번 더 스왑하면 그대로 정답이 나온다.
#dreamhack#ctf#reversing+5
2026-06-08
[🌱 새싹] 비교 직전 XOR·산술이 끼어든 검증 루프 — DreamHack rev-basic-3 풀이
blog

[🌱 새싹] 비교 직전 XOR·산술이 끼어든 검증 루프 — DreamHack rev-basic-3 풀이

rev-basic-2까지는 정답이 평문으로 메모리에 박혀 있었다. 3번은 비교 직전에 글자를 한 번 주물러 둔다 — input[i]를 i로 XOR하고 2*i를 더한 값이 .data의 테이블과 같아야 통과한다. XOR도 덧셈도 역연산이 있으니, 테이블을 떠내 거꾸로 풀면 그대로 정답이 나온다.
#dreamhack#ctf#reversing+5
2026-06-08
[💠 Platinum 1] V8을 V12로 — array-shift 길이 언더플로로 OOB부터 V8 샌드박스 탈출·RCE까지 — DreamHack V12 Revenge
blog

[💠 Platinum 1] V8을 V12로 — array-shift 길이 언더플로로 OOB부터 V8 샌드박스 탈출·RCE까지 — DreamHack V12 Revenge

"V8이 너무 느리다, V12로 갈아타자 (* 내부 함수 없이 *)" — array-shift Torque 빌트인에서 빈 배열 가드 한 줄을 주석 처리한 게 전부인 버그다. 길이 0 배열에 .shift()를 부르면 newLength = 0-1 = -1, 그게 그대로 length 필드로 들어가 length(0xFFFFFFFF) ≫ capacity 인 OOB 배열이 만들어진다. 이 글은 그 OOB에서 케이지 임의 R/W·addrof를 세우고 — 한 번은 "V8 샌드박스가 절대주소 누출을 막아 코드 실행이 불가능하다"고 잘못 결론 내렸다가 — 출제자가 의도한 정석 기법을 찾아 뒤집은 기록이다. 핵심은 WasmInstanceObject의 imported_function_targets: 임포트 함수의 호출 타깃을 담은 "케이지 안 ByteArray"가 실은 raw(샌드박스 밖) 포인터라, 케이지 쓰기만으로 import 호출을 임의 주소로 보낼 수 있다. 거기에 jump_table_start로 RWX를 직접 읽고, 셸코드 실행 순간 살아있는 r14(케이지 베이스)로 wasm 메모리를 가리켜 execve("flag_reader") — 절대주소 누출 없이 샌드박스를 빠져나와 라이브 flag까지 회수했다.
#dreamhack#ctf#pwn+6
2026-06-07
[💎 Diamond 1] Math.exp가 NaN을 잊을 때 (4) — 근데 .at()이 열려 있었다: 놓친 비-CheckBounds sink — DreamHack EXP-NaN
blog

[💎 Diamond 1] Math.exp가 NaN을 잊을 때 (4) — 근데 .at()이 열려 있었다: 놓친 비-CheckBounds sink — DreamHack EXP-NaN

3편은 "남은 출구를 전수로 두드렸지만 다 닫혔다"로 끝났다. 4편은 그 결론을 내 손으로 뒤집는 기록이다 — 3편이 본 sink는 전부 bracket 접근(`a[i]`)과 CheckBounds 계열이었는데, 딱 하나 안 본 게 있었다. `Array.prototype.at()`. 이건 별도 reducer(js-call-reducer.cc)라 경계검사를 CheckBounds가 아니라 fold 가능한 NumberLessThan 두 개 + bare LoadElement 로 한다. 패치가 그 파일을 안 건드려서 그대로 살아있고, reshape로 typer를 속이면 두 가드가 접혀 무가드 OOB read가 진짜로 열린다(자연 티어업, exit0, 결정적). 다만 store 짝이 없어 write는 여전히 막혀 있고(bracket=trap, TypedArray/fill/with 전멸, a.length는 치유), read→write 다리는 addrof/fakeobj뿐이다. 포인터 압축이 왜 reader 타입을 가르는지, 그리고 그 fakeobj 부트스트랩(타입-매칭 인접)이 왜 nursery monoculture에 막히는지 — V8 reducer 구조부터 쉘 스샷까지 한 단계씩.
#dreamhack#ctf#pwn+7
2026-06-07
[💎 Diamond 1] Math.exp가 NaN을 잊을 때 (3) — 남은 출구를 전부 두드리다: 의도된 sink마저 막혀 있었다 — DreamHack EXP-NaN
blog

[💎 Diamond 1] Math.exp가 NaN을 잊을 때 (3) — 남은 출구를 전부 두드리다: 의도된 sink마저 막혀 있었다 — DreamHack EXP-NaN

2편은 "표준 값-range 경로(CheckBounds 제거)는 11.2에서 닫혔다"까지였다. 3편은 그 뒤 — CheckBounds를 거치지 않는 *비표준 출구*를 하나하나 전부 두드린 기록이다. fill/copyWithin, foldable 빌트인, TypedArray·DataView, 요소종류 전이, 표현형 변환까지 후보 sink를 전수로 d8에 때려봤고 전부 정화/트랩/in-range로 죽었다. 그리고 가장 뜻밖의 발견 — 이 버그류의 *의도된* 해법인 new Array(len) length-construction마저 이 빌드에선 막혀 있다. 패치가 typer.cc만 건드리고 js-create-lowering의 길이 보호는 안 풀어서다. 어긋남은 살아있는데(자연 티어업에서 INT_MIN으로 발산) 받아줄 sink가 없다. 끝으로 남은 한 수 — 배포 바이너리 직접 부검.
#dreamhack#ctf#pwn+7
2026-06-07
[💎 Diamond 1] Math.exp가 NaN을 잊을 때 (2) — 이 버그를 죽인 V8 11.2 하드닝, 소스 부검 — DreamHack EXP-NaN
blog

[💎 Diamond 1] Math.exp가 NaN을 잊을 때 (2) — 이 버그를 죽인 V8 11.2 하드닝, 소스 부검 — DreamHack EXP-NaN

1편에서 타입혼동을 인덱스까지 살려 보냈지만 거기서 트랩으로 끊겼다. 2편은 "왜 트랩인가"를 V8 11.2 소스로 부검한다. CheckBounds가 기계어가 되는 경로, typer가 인덱스를 in-bounds로 증명하면 검사를 제거가 아니라 abort로 바꾸는 무조건 하드닝(kAbortOnOutOfBounds), 그리고 doar-e식 우회를 정조준해 막아둔 element-access 빌더의 두 번째 CheckBounds까지 — 소스 주석째로 들고 본다. 끝으로, 같은 시기 하드닝 켜진 V8을 실제로 뚫은 익스(구글 v8CTF·openECSC)가 왜 값-range typer 버그가 아니라 length/element-kind를 직접 손상시키는 다른 버그 클래스를 쓰는지 대조한다.
#dreamhack#ctf#pwn+7
2026-06-07
[💎 Diamond 1] Math.exp가 NaN을 잊을 때 (1) — 트리거는 됐는데 OOB가 안 자란다 — DreamHack EXP-NaN
blog

[💎 Diamond 1] Math.exp가 NaN을 잊을 때 (1) — 트리거는 됐는데 OOB가 안 자란다 — DreamHack EXP-NaN

d8 패치 한 줄이 TurboFan에게 "Math.exp는 절대 NaN을 만들지 않는다"고 거짓말을 시킨다. 하지만 Math.exp(NaN)은 NaN이다. 타입혼동 트리거까지는 깔끔하게 된다. 문제는 그 어긋남을 OOB로 키우는 단계 — NaN은 인덱스로 가는 모든 길에서 정화되고, Object.is 불리언은 폴딩되거나 Boolean으로 남고, 자연 티어업에선 어긋남이 인덱스까지 살아 도달하는데 거기서 11.2가 무조건 박아둔 kAbortOnOutOfBounds 하드닝이 트랩으로 끊어버린다. 이 글(1편)은 버그·트리거와, 공개된 typer-OOB 기법이 V8 11.2 하드닝에 어떻게 막히는지를 실측으로 끝까지 추적한다.
#dreamhack#ctf#pwn+6
2026-06-06
[🥇 Gold 1] 깨진 정규식 한 줄이 XSS를 연다 — DreamHack Fast XSS 풀이
blog

[🥇 Gold 1] 깨진 정규식 한 줄이 XSS를 연다 — DreamHack Fast XSS 풀이

FastAPI의 TemplateResponse에 임의 kwarg를 주입해 응답 헤더를 손에 넣는다. 템플릿은 autoescape라 body로는 막히지만, uvicorn의 헤더 "이름" 검증 정규식이 문자클래스 조기 종료 버그로 깨져 있어 헤더 이름에 CRLF를 넣을 수 있었다. 응답 분리로 web 오리진에 <script>를 심어 어드민 봇의 FLAG 쿠키를 탈취했다. Theori OSR CTF 출제작.
#dreamhack#ctf#web+5
2026-06-06
[🥈 Silver 3] 비밀번호 자리에 객체를 넣다 — DreamHack CProxy: Inject 풀이
blog

[🥈 Silver 3] 비밀번호 자리에 객체를 넣다 — DreamHack CProxy: Inject 풀이

쿼리는 ? 플레이스홀더로 안전하게 짰는데도 로그인이 뚫린다. express의 qs 바디 파서가 pw를 객체로 만들고, node-mysql이 그 객체를 `pw` = '1' 로 풀어쓰면서 비밀번호 검사가 항상 참이 됐다. admin_inject 계정을 탈취해 저장된 프록시 응답에서 플래그를 꺼냈다. 삽질과 캡쳐를 곁들인 풀이 노트.
#dreamhack#ctf#web+4
2026-06-06
[🥈 Silver 3] 에러 메시지 한 줄이 키를 흘린다 — DreamHack Padding Oracle 풀이
blog

[🥈 Silver 3] 에러 메시지 한 줄이 키를 흘린다 — DreamHack Padding Oracle 풀이

AES-CBC로 암호화된 관리자 글을 키 없이 읽는다. unpad() 실패가 ValueError로 새어나오는 걸 오라클 삼아 패딩 오라클 공격으로 한 바이트씩 복호했다. 고정 IV, 인증 없는 복호, 구분되는 예외 메시지가 겹쳐 암호문이 그대로 평문이 됐다. 삽질과 캡쳐를 곁들인 풀이 노트.
#dreamhack#ctf#web+4
2026-06-06
[🥈 Silver 4] switch는 느슨하게 비교한다 — DreamHack Switching Command 풀이
blog

[🥈 Silver 4] switch는 느슨하게 비교한다 — DreamHack Switching Command 풀이

PHP의 switch는 == 로 비교한다. 입력을 boolean true로 보내면 ===로 막아둔 "admin" 검사를 비껴가면서 switch case "admin"에는 걸려든다. 인증을 훔친 뒤엔 escapeshellcmd가 손대지 않는 따옴표로 명령 필터를 깨고, 출력이 안 보이는 blind 환경을 world-writable 웹루트에 파일을 떨궈 회수했다.
#dreamhack#ctf#web+5
2026-06-06
[🥉 Bronze 1] 읽을 수 없는 flag — LFI로 매니저 비번 털어 RCE — DreamHack Tomcat Manager 풀이
blog

[🥉 Bronze 1] 읽을 수 없는 flag — LFI로 매니저 비번 털어 RCE — DreamHack Tomcat Manager 풀이

image.jsp의 path traversal(LFI)로 /flag를 읽으려다 404에 막힌다. /flag가 읽기 권한 없는 실행 전용 파일이었기 때문. LFI로 conf/tomcat-users.xml의 진짜 매니저 비밀번호를 유출하고, Tomcat Manager에 웹셸 WAR을 배포해 RCE를 얻은 뒤 /flag를 "실행"해 플래그를 뽑았다.
#dreamhack#ctf#web+5
2026-06-06
[🥉 Bronze 2] 블랙리스트가 빠뜨린 백틱 — $IFS로 공백 없이 RCE — DreamHack Another Ping 풀이
blog

[🥉 Bronze 2] 블랙리스트가 빠뜨린 백틱 — $IFS로 공백 없이 RCE — DreamHack Another Ping 풀이

ping 유틸리티가 입력을 shell=True로 그대로 실행한다. 공백·세미콜론·파이프는 막았지만 백틱이 블랙리스트에 없어 명령치환이 통하고, 막힌 공백은 $IFS로 대체한다. `cat$IFS$9flag.txt` 한 줄로 flag를 ping 에러 메시지에 흘려보냈다.
#dreamhack#ctf#web+4
2026-06-06
[🥈 Silver 4] UNION으로 진짜 테이블을 찾아내는 SQL Injection — DreamHack baby-union 풀이
blog

[🥈 Silver 4] UNION으로 진짜 테이블을 찾아내는 SQL Injection — DreamHack baby-union 풀이

로그인 쿼리에 따옴표가 그대로 들어가는 전형적인 UNION SQL Injection. ' or 1=1로 주입을 확인하고, UNION SELECT 1,2,3,4로 컬럼 수와 출력 위치를 잡은 뒤, init.sql이 흘린 가짜 이름 대신 information_schema로 진짜 테이블(onlyflag)을 찾아 concat으로 플래그를 뽑았다.
#dreamhack#ctf#web+4
2026-06-05
[🥇 Gold 3] CSP nonce를 예측해서 뚫는 stored XSS — DreamHack Mini Social Media 풀이
blog

[🥇 Gold 3] CSP nonce를 예측해서 뚫는 stored XSS — DreamHack Mini Social Media 풀이

CSP가 inline script를 막지만 nonce를 Python random()으로 만든다. 응답 헤더로 새는 nonce를 624워드 모아 MT19937 상태를 복원하면 다음 nonce가 예측된다. reporter username의 stored XSS에 예측한 nonce를 박아 admin 봇 브라우저에서 /admin 플래그를 빼냈다.
#dreamhack#ctf#web+6
2026-06-05
[🥇 Gold 3] CSP nonce를 예측해서 박아 넣다 — DreamHack Dream Lectures 풀이
blog

[🥇 Gold 3] CSP nonce를 예측해서 박아 넣다 — DreamHack Dream Lectures 풀이

강의 신청 사이트의 reason 필드가 autoescape false로 그대로 렌더된다. 진짜 벽은 CSP nonce인데, 이 nonce가 16비트 LFSR로 생성되고 매 응답 헤더에 평문으로 샌다. 한 번 새어 나온 nonce로 LFSR을 복원해 다음 값을 예측하고, apply 한 요청 안에서 봇이 페이지를 읽는 타이밍에 맞춰 script nonce를 박아 CSP를 통과시킨 뒤 navigation으로 플래그를 빼냈다.
#dreamhack#ctf#web+6
2026-06-05
[🥇 Gold 3] 쿠키 한 줄로 Thymeleaf 뷰 이름을 갈아끼우다 — DreamHack spring-view 풀이
blog

[🥇 Gold 3] 쿠키 한 줄로 Thymeleaf 뷰 이름을 갈아끼우다 — DreamHack spring-view 풀이

Spring + Thymeleaf 앱에서 lang 쿠키가 그대로 뷰 이름이 된다. 프래그먼트 전처리 __${...}__ 로 SpEL을 실행하는 View-Name SSTI를 잡고, java/class/Runtime 블랙리스트와 쿠키 RFC6265 제약(공백·콤마·세미콜론 금지), 그리고 원격 Java 8 환경까지 차례로 우회해 /flag.txt 를 읽어낸다.
#dreamhack#ctf#web+5
2026-06-05
[🥉 Bronze 1] innerHTML에 넣은 <script>는 안 뜬다 — DreamHack xss-2 풀이
blog

[🥉 Bronze 1] innerHTML에 넣은 <script>는 안 뜬다 — DreamHack xss-2 풀이

vuln 페이지가 param을 innerHTML로 꽂는다. innerHTML로 삽입된 script는 실행되지 않으니 img/onerror로 우회해 봇의 flag 쿠키를 읽고, 공용 /memo 저장소로 흘려보내 회수했다.
#dreamhack#ctf#web+4
2026-06-05
[🥉 Bronze 2] 백업 기능이 쿠키를 그대로 셸에 넘긴다 — DreamHack Simple Note Manager 풀이
blog

[🥉 Bronze 2] 백업 기능이 쿠키를 그대로 셸에 넘긴다 — DreamHack Simple Note Manager 풀이

메모 백업 기능이 backup-timestamp 쿠키를 그대로 cp 명령에 끼워 넣고 shell=True로 실행한다. 출력이 돌아오지 않는 블라인드 OS 커맨드 인젝션이라, 컨테이너 안의 curl로 flag를 읽어 앱 자신의 /create_note에 다시 집어넣고 /notes에서 회수했다.
#dreamhack#ctf#web+4
2026-06-05
[🌱 새싹] 정답이 4바이트씩 끊겨 박힌 배열 — DreamHack rev-basic-2 풀이
blog

[🌱 새싹] 정답이 4바이트씩 끊겨 박힌 배열 — DreamHack rev-basic-2 풀이

rev-basic-1이 글자마다 cmp를 펼친 코드였다면, 2번은 루프 하나로 정답 배열과 비교한다. 비교 대상이 byte가 아니라 .data의 4바이트 정수 배열이라 한 칸이 4바이트씩이다. 각 원소의 저바이트만 모으면 정답. objdump로 배열을 떠내 디코드하고 wine으로 Correct를 확인했다.
#dreamhack#ctf#reversing+4
2026-06-04
[🌱 새싹] 한 글자씩 cmp — 코드에 흩어진 상수 모으기 — DreamHack rev-basic-1 풀이
blog

[🌱 새싹] 한 글자씩 cmp — 코드에 흩어진 상수 모으기 — DreamHack rev-basic-1 풀이

rev-basic-0이 strcmp 한 방이었다면, 1번은 입력을 한 글자씩 cmp로 비교한다. 검증 함수에 흩어진 비교 상수 21개를 주소순으로 모아 ASCII로 디코드하면 정답이 나온다. objdump로 cmp 체인을 뽑고 wine으로 Correct를 확인한 과정.
#dreamhack#ctf#reversing+4
2026-06-04
[🌱 새싹] strcmp 하나가 전부 — DreamHack rev-basic-0 풀이
blog

[🌱 새싹] strcmp 하나가 전부 — DreamHack rev-basic-0 풀이

입력을 받아 Correct/Wrong을 출력하는 x86-64 PE. 검증 함수는 입력을 .rdata에 평문으로 박힌 문자열과 strcmp 비교할 뿐이다. 디스어셈블로 비교 대상 주소를 찾아 문자열을 그대로 꺼내 답을 구하고, wine으로 Correct를 확인한 과정.
#dreamhack#ctf#reversing+4
2026-06-04
[🥉 Bronze 2] escapeshellcmd가 안 막는 공백 — curl 인자 주입으로 웹셸 RCE — DreamHack Command Injection Advanced 풀이
blog

[🥉 Bronze 2] escapeshellcmd가 안 막는 공백 — curl 인자 주입으로 웹셸 RCE — DreamHack Command Injection Advanced 풀이

escapeshellcmd는 셸 메타문자는 막지만 공백과 하이픈은 그대로 둔다. curl 명령에 -o 인자를 끼워 넣어 PHP 웹셸을 웹루트 cache/에 떨군 뒤, 그 웹셸로 실행전용 바이너리 /flag를 돌려 플래그를 얻은 과정을 정리했다.
#dreamhack#ctf#web+5
2026-06-04
[🥉 Bronze 1] SQL인 척하는 JSON, 진짜 구멍은 WebDAV PUT — DreamHack Really Not SQL 풀이
blog

[🥉 Bronze 1] SQL인 척하는 JSON, 진짜 구멍은 WebDAV PUT — DreamHack Really Not SQL 풀이

로그인은 user/<id>.json 파일을 읽는 JSON 유저 저장소다. admin 비밀번호는 모르지만, Apache의 user/ 디렉터리에 mod_dav가 켜져 있고 .htaccess는 DELETE만 막는다. PUT으로 admin.json을 내가 아는 해시로 덮어써 admin이 된 뒤 flag.php를 연 과정.
#dreamhack#ctf#web+5
2026-06-04
[🥉 Bronze 1] 봇의 admin 헤더를 빌려 /whoami 털기 — DreamHack Are you admin? 풀이
blog

[🥉 Bronze 1] 봇의 admin 헤더를 빌려 /whoami 털기 — DreamHack Are you admin? 풀이

intro 페이지의 name이 `| safe`로 이스케이프 없이 렌더되는 reflected XSS. 봇은 모든 요청에 admin Basic-Auth 헤더를 자동으로 붙이고 다니므로, 봇 컨텍스트에서 /whoami를 fetch하면 admin으로 인증돼 FLAG가 나온다. 이를 webhook으로 빼낸 과정.
#dreamhack#ctf#web+5
2026-06-04
[🥉 Bronze 2] 봇의 쿠키를 /memo로 흘려 회수하기 — DreamHack xss-1 풀이
blog

[🥉 Bronze 2] 봇의 쿠키를 /memo로 흘려 회수하기 — DreamHack xss-1 풀이

/vuln이 입력을 이스케이프 없이 그대로 뱉는 reflected XSS. flag를 쿠키로 들고 페이지를 방문하는 봇에게 스크립트를 주입해 document.cookie를 같은 서버의 /memo로 흘려보내고, 그 memo를 직접 읽어 플래그를 회수한 과정을 정리했다.
#dreamhack#ctf#web+5
2026-06-04
[🥉 Bronze 3] sleep 한 줄로 KEY를 흘리게 만들기 — DreamHack BypassIF 풀이
blog

[🥉 Bronze 3] sleep 한 줄로 KEY를 흘리게 만들기 — DreamHack BypassIF 풀이

Admin KEY를 모르는데 KEY는 md5(flag)다. 명령 필터를 통과하는 sleep으로 일부러 타임아웃을 내면 except 분기가 KEY를 응답에 그대로 흘린다. 유출한 KEY를 다시 제출해 플래그를 받아낸 과정을 정리했다.
#dreamhack#ctf#web+4
2026-06-04
[🥉 Bronze 3] X-User·Referer 헤더 위조로 비밀 문서 읽기 — DreamHack DreamDocs 풀이
blog

[🥉 Bronze 3] X-User·Referer 헤더 위조로 비밀 문서 읽기 — DreamHack DreamDocs 풀이

문서 열람 권한을 Referer와 X-User 헤더로만 판단하는 게시판이다. 둘 다 요청자가 마음대로 보내는 값이라, X-User: admin 과 Referer: /share 를 위조하면 confidential 문서의 본문(FLAG)이 그대로 열린다.
#dreamhack#ctf#web+6
2026-06-04
[💎 Diamond 3] 절반만 보여주고 그마저 절반은 누락 — 그래도 다음 출력을 맞힌다 (Fauna)
blog

[💎 Diamond 3] 절반만 보여주고 그마저 절반은 누락 — 그래도 다음 출력을 맞힌다 (Fauna)

상위 절반만 출력하고 50% 확률로 누락되는 곱셈 LCG. 곱수가 미지라 Coppersmith는 ℓ/n=0.5 벽을 못 넘는다. Stern 알고리즘(Martinez Attack 3)으로 연속 9개 출력만으로 곱수를 복원하고, 상태를 walk해 다음 출력을 예측 → AES 키 → flag.
#dreamhack#ctf#crypto+6
2026-06-04
[🥉 Bronze 2] GIF 폴리글랏으로 PHP 웹셸 업로드 — DreamHack Image Uploader 풀이
blog

[🥉 Bronze 2] GIF 폴리글랏으로 PHP 웹셸 업로드 — DreamHack Image Uploader 풀이

확장자와 MIME 타입 검사를 AND(&&)로 묶은 업로더다. 둘 중 하나만 통과하면 되는 허점이라, GIF89a 매직바이트를 앞에 붙인 .php 파일이 image/gif 로 인식돼 그대로 업로드된다. 웹셸을 올려 RCE로 플래그를 읽는 과정을 정리했다.
#dreamhack#ctf#web+6
2026-06-04
[🥉 Bronze 3] 숨긴 _id를 ObjectId 예측으로 복원해 비밀글 읽기 — DreamHack mongoboard 풀이
blog

[🥉 Bronze 3] 숨긴 _id를 ObjectId 예측으로 복원해 비밀글 읽기 — DreamHack mongoboard 풀이

게시판이 비밀글의 _id만 null로 가렸지만, MongoDB ObjectId는 시각·랜덤·카운터로 이뤄진 예측 가능한 값이다. 보이는 글들의 _id와 비밀글의 publish_date만으로 숨긴 _id를 복원해 본문(FLAG)을 읽는 과정을 정리했다.
#dreamhack#ctf#web+5
2026-06-04
[🥈 Silver 4] CouchDB 특수 엔드포인트로 인증 우회 — DreamHack NoSQL-CouchDB 풀이
blog

[🥈 Silver 4] CouchDB 특수 엔드포인트로 인증 우회 — DreamHack NoSQL-CouchDB 풀이

로그인 비교식 result.upw === req.body.upw 의 빈틈. uid에 CouchDB 특수 엔드포인트 _all_docs 를 넣으면 응답에 upw 필드가 없어 undefined가 되고, upw를 아예 보내지 않으면 undefined === undefined 로 비밀번호 없이 인증을 통과해 FLAG를 가져온다.
#dreamhack#ctf#web+4
2026-06-04
[🥉 Bronze 1] SVG 태그 allowlist를 우회한 innerHTML XSS로 쿠키 탈취 — DreamHack PTML 풀이
blog

[🥉 Bronze 1] SVG 태그 allowlist를 우회한 innerHTML XSS로 쿠키 탈취 — DreamHack PTML 풀이

업로드한 SVG를 innerHTML로 그대로 삽입하는데, 검증은 태그 이름만 allowlist로 본다. 허용 태그(animate·image·svg)에 이벤트 핸들러 속성을 달아 XSS를 띄우고, 봇이 들고 있는 flag 쿠키를 동기 XHR로 유출하는 과정을 정리했다.
#dreamhack#ctf#web+5
2026-06-04
[🥉 Bronze 4] 부분 일치 누출로 4자리 사물함 번호 복원 — DreamHack random-test 풀이
blog

[🥉 Bronze 4] 부분 일치 누출로 4자리 사물함 번호 복원 — DreamHack random-test 풀이

로그인 폼이 전체 값이 아니라 입력 길이만큼의 prefix만 비교하면, 한 글자씩 정답을 떠보는 oracle이 된다. 2.1억 조합짜리 사물함 번호+비밀번호를 176번의 요청으로 복원해 플래그를 얻는 과정을 정리했다.
#dreamhack#ctf#web+5
2026-06-04
[🥇 Gold 2] URLDecode와 curl의 파서 차이로 SSRF 우회 — DreamHack Strong BypassIF 풀이
blog

[🥇 Gold 2] URLDecode와 curl의 파서 차이로 SSRF 우회 — DreamHack Strong BypassIF 풀이

서버는 URLDecode 후 UriComponentsBuilder로 host를 검증하지만, 실제 요청은 디코딩하지 않은 raw URL을 curl에 그대로 넘긴다. 이 한 끗 차이로 검증기는 localhost로, curl은 외부 서버로 보내 Access-Token을 유출하고 /api/flag를 직접 호출했다.
#dreamhack#ctf#web+4
2026-06-01
[💎 Diamond 4] 깃발 세 조각을 다항식 소거로 다시 맞추기 — DreamHack f, l and ag 풀이
blog

[💎 Diamond 4] 깃발 세 조각을 다항식 소거로 다시 맞추기 — DreamHack f, l and ag 풀이

flag 를 f·l·ag 세 조각으로 쪼개 각각·전체를 e=257 RSA 로 암호화한 문제. Franklin–Reiter 와 Gröbner 가 막히는 지점을 짚고, ℤ/N 위에서 monic 없이 변수를 소거하는 의사 나눗셈으로 비율 f/ag, l/ag 를 뽑은 뒤 LLL 로 평문을 복원한다.
#dreamhack#ctf#crypto+8
2026-05-30
[💎 Diamond 4] 난독화된 안드로이드 DRM을 통째로 빌려 쓰기 — DreamHack Dream DRM 풀이
blog

[💎 Diamond 4] 난독화된 안드로이드 DRM을 통째로 빌려 쓰기 — DreamHack Dream DRM 풀이

request_book의 id 파라미터 SQL Injection으로 서버의 임의 파일(/flag)을 암호문 상태로 읽어내고, 패킹된 native DRM 라이브러리를 NDK 하니스 + dlopen + 가짜 JNIEnv로 직접 호출해 복호화 오라클로 삼는 과정을 정리한다. 오프라인 크래킹·APK 재서명·MITM 등 막다른 길까지 전부 기록한 Theori 채용 CTF 다이아 4 풀이.
#dreamhack#ctf#web+7
2026-05-29
[🌱 새싹] 내부 전용 API를 ../ 한 방으로 뚫기 — DreamHack Path Traversal 풀이
blog

[🌱 새싹] 내부 전용 API를 ../ 한 방으로 뚫기 — DreamHack Path Traversal 풀이

127.0.0.1 에서만 호출 가능한 internal API 서버. 사용자 입력이 그대로 내부 요청 URL에 들어가는 SSRF + Path Traversal 취약점을 이용해, `../flag` 한 줄로 접근 제한된 /api/flag 엔드포인트의 플래그를 빼낸다.
#dreamhack#ctf#web+4
2026-05-29
[💎 Diamond 4] jsdom ≠ Chrome 파서 차이로 터지는 mutation XSS — DreamHack web-dreamshop 풀이
blog

[💎 Diamond 4] jsdom ≠ Chrome 파서 차이로 터지는 mutation XSS — DreamHack web-dreamshop 풀이

프론트엔드 번들에 jsdom을 끼워 DOMPurify로 sanitize하는 순간, "검사한 DOM"과 "렌더하는 DOM"이 달라져 mutation XSS가 열린다. vue-router의 %2F 디코드와 axios protocol-relative 처리로 admin 봇의 요청 호스트를 탈취하고, 그 위에 mXSS를 얹어 admin 권한으로 FLAG를 "구매"하는 DreamHack 다이아4 web 문제 풀이.
#dreamhack#ctf#web+7
2026-05-29
[💠 Platinum 1] Tropical Algebra 서명 스킴을 뒤집어 본 기록 — DreamHack Tropical Santa 풀이
blog

[💠 Platinum 1] Tropical Algebra 서명 스킴을 뒤집어 본 기록 — DreamHack Tropical Santa 풀이

Chen–Grigoriev–Shpilrain의 트로피컬 다항식 기반 서명 스킴이 어떻게 깨지는지 추적한 기록. formal vs functional equality, 트로피컬 나눗셈의 비유일성, 그리고 한 줄짜리 위조 공격까지.
#dreamhack#ctf#crypto+5
2026-05-28
[🥉 Bronze 3] base64 안에 숨겨진 ASCII 배열 — DreamHack 64se64 풀이
blog

[🥉 Bronze 3] base64 안에 숨겨진 ASCII 배열 — DreamHack 64se64 풀이

zip 안 index.html의 hidden input에 박힌 base64 문자열을 디코딩하면 ASCII 코드 배열을 chr()로 합치는 파이썬 스크립트가 나온다. 그대로 실행하면 플래그가 출력된다.
#dreamhack#ctf#misc+4
2026-05-26
[⭐⭐⭐] ord마저 막힌 곳에서 글자를 캐내는 법 — DreamHack SQL Injection Bypass WAF Advanced 풀이
blog

[⭐⭐⭐] ord마저 막힌 곳에서 글자를 캐내는 법 — DreamHack SQL Injection Bypass WAF Advanced 풀이

union·select·from·and·or·admin·공백까지 막힌 WAF 환경에서 `||` `&&` `idx=` `ascii()` `substr()` 조합으로 admin 행을 매칭하고, ASCII 이진 탐색으로 44자리 플래그를 추출한 풀이입니다. `ord()`가 `or` 부분문자열 때문에 차단되는 함정이 핵심.
#dreamhack#ctf#web+5
2026-05-24
[⭐⭐⭐⭐] 디버그 엔드포인트가 세션 전체를 토해낸다 — DreamHack session-basic 풀이
blog

[⭐⭐⭐⭐] 디버그 엔드포인트가 세션 전체를 토해낸다 — DreamHack session-basic 풀이

Flask 세션 인증 서비스에서 개발자가 "나중에 고칠게" 주석으로 남겨둔 /admin 엔드포인트가 session_storage 딕셔너리 전체를 JSON으로 반환한다. 서버 부팅 시 미리 생성된 admin sessionid를 그대로 가져와 쿠키에 박으면 끝.
#dreamhack#ctf#web+4
2026-05-23
OKLCH 색 공간을 3D로 뜯어보기 — three.js 색역 뷰어 제작기
blog

OKLCH 색 공간을 3D로 뜯어보기 — three.js 색역 뷰어 제작기

OKLAB/OKLCH 색 공간을 정적 그림이 아니라 직접 돌려보고 싶어서 /playground 에 인터랙티브 3D 뷰어를 붙였다. React Three Fiber + culori 로 색역을 점구름으로 그리고, sRGB↔OKLab 좌표계를 토글하고, 그라디언트 보간 경로의 "함몰"을 눈으로 보이게 만든 과정 — Next.js 16 의 ssr:false 함정과 three.js 정점색 색공간 함정까지 정리한다.
#color#oklch#three.js+3
2026-05-22
autopwn 개발기 ⑤ — 킬체인이 진짜 "풀체인"이 된 날 (Sliver proto 지옥 · claude-shim · LAN MITM)
blog

autopwn 개발기 ⑤ — 킬체인이 진짜 "풀체인"이 된 날 (Sliver proto 지옥 · claude-shim · LAN MITM)

recon·exploit 까지만 돌던 파이프라인에 C2 implant 빌드와 post-ex, LAN MITM 을 붙여 킬체인을 닫았다. Sliver v1.7.3 의 protobuf field 번호가 sliver-py 와 어긋나 implant 빌드가 죽던 문제를 vendored proto + raw gRPC 로 우회하고, AI escalation 백엔드는 호스트의 claude CLI 를 thin proxy(claude-shim)로 분리했으며, pytest 50개로 처음 테스트 그물을 깔았다.
#autopwn#sliver#c2+2
2026-05-20
autopwn 개발기 ④ — Homepage 어드민 콘솔과 AI 게이트의 3중 잠금
blog

autopwn 개발기 ④ — Homepage 어드민 콘솔과 AI 게이트의 3중 잠금

Phase 1 백엔드 위에 zino.kr 어드민 콘솔(4탭 + SSE 라이브뷰)을 얹고, AI escalation을 안전하게 켜는 3중 잠금 (per-run opt-in · per-playbook disallow · scope 재검증)을 코드로 강제. nmap adapter의 결과 파싱 누락도 같이 패치.
#autopwn#nextjs#sse+2
2026-05-17
autopwn 개발기 ③ — 첫 라이브 런, SSE 67줄, 그리고 남은 nmap 버그
blog

autopwn 개발기 ③ — 첫 라이브 런, SSE 67줄, 그리고 남은 nmap 버그

scope/allowlist 등록 → /scope/check 거부·허가 동작 확인 → /playbooks/run POST → SSE 라이브 관찰 → 15분 후 succeeded. 백엔드 골격은 의도대로 작동, 다만 nmap adapter의 결과 파싱에 작은 구멍이 남았다.
#autopwn#sse#nmap+2
2026-05-17
autopwn 개발기 ② — Phase 1을 막은 세 개의 함정 (YAML scalar · grpcio · proxychains)
blog

autopwn 개발기 ② — Phase 1을 막은 세 개의 함정 (YAML scalar · grpcio · proxychains)

Phase 0~1 빌드는 깔끔하게 끝났는데, 첫 검증 시도에서 msf 컨테이너가 무한 재시작했고 API가 import 단계에서 죽었으며 nmap이 proxychains에 거부당했다. 세 군데 모두 코드 자체보다는 "연결 면적의 미세 균열"이라 기록 가치가 있었다.
#autopwn#docker#proxychains+2
2026-05-17
autopwn 개발기 ① — 왜 자가 호스팅 풀 킬체인 도구를 직접 짜기 시작했나
blog

autopwn 개발기 ① — 왜 자가 호스팅 풀 킬체인 도구를 직접 짜기 시작했나

외부 SaaS 펜테스트 플랫폼 대신 본인 자산·CTF·서면 동의 engagement만 다루는 자가 호스팅 풀 킬체인 오케스트레이션을 직접 짜기로 결정한 이유와, Phase 0~1 빌드 전에 못박은 여덟 가지 설계 결정을 정리한다.
#autopwn#pentest#opsec+2
2026-05-17
[⭐⭐⭐] SQLi + SSRF 더블 슬래시 필터 우회 — DreamHack admin only 풀이
blog

[⭐⭐⭐] SQLi + SSRF 더블 슬래시 필터 우회 — DreamHack admin only 풀이

SQLite UNION 인젝션으로 admin 비밀번호를 탈취·로그인하고, /profile의 SSRF를 통해 //getflag (더블 슬래시) 경로 우회로 /getflag 필터를 bypass해 FLAG를 획득하는 풀이.
#dreamhack#ctf#web+6
2026-04-30
[⭐] Switch는 작동한다, 다만 모든 분기가 진실을 말하지 않을 뿐 — DreamHack Control-Flow: mirage 풀이
blog

[⭐] Switch는 작동한다, 다만 모든 분기가 진실을 말하지 않을 뿐 — DreamHack Control-Flow: mirage 풀이

44개 상태를 dispatch table로 돌리는 state machine, 그리고 PRNG 조건처럼 보이지만 실행 결과에 아무런 영향을 주지 않는 opaque predicate. 정적 분석만으로 jump table을 추출하고 변환 순서를 역추적해 플래그를 구하는 과정을 단계별로 정리한다.
#dreamhack#ctf#reversing+3
2026-04-30
사이트 보안점검 후기
blog

사이트 보안점검 후기

오랜만에 Next.js 사이트를 직접 뒤적거리며 보안 점검을 했다. 발견한 문제들과 어떻게 고쳤는지 실제 커맨드 결과랑 같이 정리.
#security#nextjs#hardening
2026-04-03
[⭐⭐⭐] TAB 하나로 필터 열 개를 뚫다 — DreamHack XSS Filtering Bypass Advanced 풀이
blog

[⭐⭐⭐] TAB 하나로 필터 열 개를 뚫다 — DreamHack XSS Filtering Bypass Advanced 풀이

script, javascript, document, location, (, )까지 10개 이상의 키워드를 차단하는 XSS 필터. 그런데 javas\tcript처럼 TAB 문자(\t)를 키워드 중간에 끼우면 필터는 통과하고 브라우저는 그대로 실행한다. WHATWG URL 스펙이 정의한 정규화 동작과 Python 문자열 필터 사이의 갭을 파고들어 쿠키를 탈취하고 FLAG를 획득하는 과정을 단계별로 정리한다.
#dreamhack#ctf#web+4
2026-04-01
[⭐⭐⭐⭐⭐] 한 번 막히고 나서야 보였던 체인: DreamHack EZ-Anti-LLM Pingback SSRF 풀이
blog

[⭐⭐⭐⭐⭐] 한 번 막히고 나서야 보였던 체인: DreamHack EZ-Anti-LLM Pingback SSRF 풀이

WordPress 6.9.1 Pingback Blind SSRF를 이용해 2-Hop 체인으로 내부 Flag 서버의 값을 외부로 끌어낸 DreamHack Level 5 문제 풀이. 삽질 포인트부터 최종 익스플로잇 흐름까지 차근차근 정리했다.
#dreamhack#ctf#ssrf+5
2026-03-31
[⭐⭐] printf 한 줄로 GOT를 갈아끼워 셸 따기 — DreamHack basic_exploitation_002 풀이
blog

[⭐⭐] printf 한 줄로 GOT를 갈아끼워 셸 따기 — DreamHack basic_exploitation_002 풀이

printf(buf)의 Format String 취약점을 이용해 exit@got를 get_shell 주소로 덮어쓰고 셸을 획득하는 과정을 단계별로 정리합니다. pwntools fmtstr_payload로 40바이트 페이로드 하나로 FLAG 획득.
#dreamhack#ctf#pwn+4
2026-03-31
[🥈 Silver 4] 참/거짓만 캐물어 admin 비밀번호를 한 글자씩 — DreamHack Secret Data 풀이
blog

[🥈 Silver 4] 참/거짓만 캐물어 admin 비밀번호를 한 글자씩 — DreamHack Secret Data 풀이

/search 엔드포인트의 SQL 문자열 직접 결합 취약점을 이용해 블라인드 boolean 방식으로 admin 비밀번호를 한 글자씩 추출하고, /admin에서 최종 플래그를 획득한 전 과정을 정리합니다.
#dreamhack#ctf#sqli+3
2026-03-31
[🥈 Silver 3] 미리보기 기능을 타고 내부 Docker API까지 — DreamHack Tap Tap 풀이
blog

[🥈 Silver 3] 미리보기 기능을 타고 내부 Docker API까지 — DreamHack Tap Tap 풀이

Internal API Testing Tool의 검증 우회를 통해 SSRF를 성공시키고, 내부 Docker API에서 컨테이너 로그로 최종 플래그를 획득한 전 과정을 정리합니다.
#dreamhack#ctf#ssrf+3
2026-03-31
Windows 이벤트 로그 기반 공격 흐름 분석 — Event ID 4624 중심
blog

Windows 이벤트 로그 기반 공격 흐름 분석 — Event ID 4624 중심

Event ID 4624를 출발점으로, 로그온 세션의 문맥을 따라가며 공격 흐름을 읽는 방법을 정리합니다. Logon Type 해석, 권한 상승·프로세스 실행 연계, 실무 탐지 기준까지 포함합니다.
#forensics#windows#log-analysis+2
2026-03-25
Windows 이벤트 로그 기반 포렌식 분석 흐름 정리
blog

Windows 이벤트 로그 기반 포렌식 분석 흐름 정리

Windows Security 로그를 기준으로 로그인, 권한, 프로세스, 후속 행위를 연결해서 보는 흐름을 정리합니다.
#forensics#windows#log-analysis+1
2026-03-24
Linux Kernel – 5 Kernel compilie 🛠️
blog

Linux Kernel – 5 Kernel compilie 🛠️

Linux Kernel – 5 Kernel compilie 🛠️ 라이브러리 설치 커널 컴파일 라즈베리파이 커널 빌드(컴파일), 커널 모듈 개발용 라이브러리 설치 * bc bison flex libssl-dev install 설치 apt-get install git bc bison flex libssl-dev 추가 필요 예상되는 패키지 설치 sudo apt-
#kernel-compilation#linux-kernel#makefile+1
2025-05-23
Linux Kernel – 4 Kernel system configuration🧠
blog

Linux Kernel – 4 Kernel system configuration🧠

Linux Kernel – 4 Kernel system configuration🧠 라즈베리파이에서 커널 개발 또는 컴파일에 필요한 시스템 정보를 확인하기 위한 명령어 확인 커널 버전 확인 root@raspberrypi:/home/jinho# uname -r 6.12.25+rpt-rpi-v8 전체 커널 정보 (컴파일러 포함) root@raspberrypi:/
#ARMv8#DeviceTree#KernelDevelopment+1
2025-05-22
Linux Kernel – 2 Kernel vendor, architecture 🧠
blog

Linux Kernel – 2 Kernel vendor, architecture 🧠

Linux Kernel – 2 Kernel vendor, architecture 🧠 Vendor별 커널 관점 CPU 핵심 구성 요소별 역할 데이터 전송 흐름 (비트 단위) 주요 아키텍처별 비트 구조 비교 CPU, SoC, 보드 벤더별 하드웨어 구조 차이를 커널 관점에서 설명 각 아키텍처의 비트 구조와 데이터 처리 흐름을 중심으로 정리 Vendor별 커널 관
#ARMv7#ARMv8#BitWidth+5
2025-05-15
Linux Kernel – 3 System Call Flows and Kernel Component Differences by Architecture🧠
blog

Linux Kernel – 3 System Call Flows and Kernel Component Differences by Architecture🧠

Linux Kernel – 3 System Call Flows and Kernel Component Differences by Architecture🧠 아키텍처별 시스템 콜 흐름과 커널 변경 컴포넌트 아키텍처별 시스템 콜 흐름 비교 아키텍처가 달라지면 커널 내부에서 아키텍처 의존성이 강한 부분들이 직접적으로 영향을 받는다. 특히 시스템 콜과 예외 처리, 컨
#ArchitectureSpecificCode#ARMv8#DeviceTree+2
2025-05-15
Linux Kernel – 1 Linux Kernel Overview 🧠
blog

Linux Kernel – 1 Linux Kernel Overview 🧠

Linux Kernel – 1 Linux Kernel Overview 🧠 리눅스를 알아야 하는 이유 리눅스가 인기 있는 이유 쓰이는 곳 커널과 운영체저와의 차이 커널은 왜 존재 하는가? 커널 내부에 실제로 구현된 주요 기능 항목 커널 시스템 구조 커널의 정의와 역할 커널은 운영체제의 핵심 부분 중 하나다. 항상 메모리에 상주하면서 하드웨어와 응용 프로그램
#EmbeddedAndIoTwithLinux#KernelArchitecture#LinuxAutomationAndOps+3
2025-05-14
apache access.log 접근 IP TOP 10 선정/차단 🏆
blog

apache access.log 접근 IP TOP 10 선정/차단 🏆

apache access.log 접근 IP TOP 10 선정/차단 🏆 access.log ? log 포맷 cat, awk 활용 sort, uniq 활용 head 활용 IP 차단 Apache access.log Apache Access Log는 Apache 웹 서버에서 발생한 HTTP 요청에 대한 로그 정보를 기록하는 파일 웹 서버의 활동을 추적하고 모니터링
#.htaccess#Apache#Command+3
2024-02-04
Frida 활용 안드로이드 모의해킹 🤖 #5
blog

Frida 활용 안드로이드 모의해킹 🤖 #5

Frida 활용 안드로이드 모의해킹 🤖 #5 JavaScript API 함수와 CLI Frida JavaScript API 기본 문법 1. java.perform(fn) 함수는 현재 스레드에서 주어진 함수를 동기적으로 실행 Android 애플리케이션의 메인 스레드에서 자바 코드를 실행하는 데 사용 Java.perform(function () { // 여기
#Android Hacking#Frida#frida-server+2
2024-01-29
Frida 활용 안드로이드 모의해킹 🤖 #3
blog

Frida 활용 안드로이드 모의해킹 🤖 #3

Frida 활용 안드로이드 모의해킹 🤖 #3 Frida 설치 & 실행 Frida Tools 설치 Frida 16.1.11 Version 설치 확인 Emulator Bit 확인 Frida Server 설치 버전과 Bit 맞는 frida-server 패키지 설치 설치 경로 https://github.com/frida/frida/releases 압축 해제 후 P
#Android Hacking#Frida#frida-server+2
2024-01-27
Frida 활용 안드로이드 모의해킹 🤖 #4
blog

Frida 활용 안드로이드 모의해킹 🤖 #4

Frida 활용 안드로이드 모의해킹 🤖 #4 프로세스, 트레이스, 디바이스 제어 frida-trace Frida를 사용하여 애플리케이션의 함수 호출을 동적으로 추적하고 출력하는 도구 1. Nox 애뮬레이터로 Chrome 실행 2. 실행 프로세스 확인 $ frida-ps -Ua 3. 프로세스 추적 -i 옵션 : 추적할 함수의 이름을 지정하는 데 사용. 지정한
#Android Hacking#Frida#frida-server+2
2024-01-27
Frida 활용 안드로이드 모의해킹 🤖 #1
blog

Frida 활용 안드로이드 모의해킹 🤖 #1

Frida 활용 안드로이드 모의해킹 🤖 #1 Nox 플레이어 설치 Frida 주요 기능 Frida 환경 구성 Nox 설치, 설정 Nox ADB 환경 변수 설정 애뮬레이터 Shell 연결 Emulator 정보 확인 Frida 주요 기능 Hooking 및 함수 변조 앱의 실행 중 함수에 접근하여 수정, 동적 코드 변경이 가능 인터셉트 및 로깅 메서드 호출, 인
#Android Hacking#Frida#frida-server+2
2024-01-18
WordPress Redis object cache 🧹
blog

WordPress Redis object cache 🧹

WordPress Redis object cache 🧹 주요 기능 데이터 구조 Redis 설치 & 실행 redis.conf 수정 Server 구동 Wordpress 구성 Redis object cache 주요 기능 캐시 성능 향상 WordPress Redis object cache는 데이터를 메모리에 저장하여 데이터 검색 및 로드 속도를 향상 분산 캐싱 R
#Redis#Redis object cache#wordpress
2024-01-18
Frida 활용 안드로이드 모의해킹 🤖 #2
blog

Frida 활용 안드로이드 모의해킹 🤖 #2

Frida 활용 안드로이드 모의해킹 🤖 #2 Python 설치를 위한 Anaconda 설치 Python Anaconda 주요 기능 가상환경 관리 Anaconda는 가상 환경을 생성하고 관리하는데 용이하며, 여러 프로젝트 간에 패키지 충돌을 방지합니다. 패키지 관리 Anaconda는 패키지를 쉽게 설치, 업데이트, 제거할 수 있는 편리한 패키지 관리자인 co
#Android Hacking#Frida#frida-server+2
2024-01-18
Virtualbox 고정 할당 저장소 용량 늘리기
blog

Virtualbox 고정 할당 저장소 용량 늘리기

Virtualbox 고정 할당 저장소 용량 늘리기 📦 !! 고정으로 할당된 vdi 파일은 용량 변경 시 동적 할당으로 변경해 준 뒤 진행해야 한다. 1. 파일 확인 Virtualbox Manager.exe 기본 저장 경로 : C:
rogram Files\Oracle\VirtualBox 2. 기존 vdi resize 명령어 실행 C:
rogram File
#Storage#Virtualbox
2023-03-26
Start Nessus on Linux – 2 Nessus Scanning 🕵🏻‍♂️
blog

Start Nessus on Linux – 2 Nessus Scanning 🕵🏻‍♂️

Start Nessus on Linux – 2 Nessus Scanning 🕵🏻‍♂️ 스캐닝 템플릿 Target 지정 스캔 시작 로그 확인 결과 확인 Nessus 취약점 스캐너 다운로드 이후 취약점 스캐닝 방법을 공유합니다. ! 주의 Scanning 시도는 허가되지 않은 시스템에서 진행하면 안되며, Scan 간 트래픽 발생이 가능해 사전에 허가 받은 시스템
#hacking#nessus#nessus install+1
2023-03-20
Kali Linux 에서 Pycharm 설치하기
blog

Kali Linux 에서 Pycharm 설치하기

Kali Linux 에서 Pycharm 설치하기 설치 실행 Kali linux 내 Python 통합 개발 환경인 Pycharm을 설치하는 방법을 공유합니다. 페이지 내 Pycharm 무료 버전인 Community 버전을 다운로드 해줍니다. Pycharm 다운로드 페이지 - https://www.jetbrains.com/pycharm/download/#sec
#linux#pycharm
2023-02-06
외부 서버 파일 Upload/Download ☕
blog

외부 서버 파일 Upload/Download ☕

외부 서버 파일 Upload/Download ☕ ■ JAVA FileDownload package remoteFileDownload; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.file.Files; import java.nio.file
#File download#File upload#java
2022-09-25
Oracle sysdba 권한 부여 🔮
blog

Oracle sysdba 권한 부여 🔮

Oracle sysdba 권한 부여 🔮 Oracle DB 일반 사용자에게 grant sysdba to c##user;와 같이 sysdba 권한을 부여할 경우 ORA-65175: 로컬에서 루트에 SYSDBA 권한을 부여할 수 있습니다. 방법 Password file 생성 $ orapwd file=$ORACLE_HOME/dbs/PASSWORD password=
#authorization#Oracle sysdba
2022-09-24
Install Oracle DB 12 ON Radhat Linux 7.7 🔮
blog

Install Oracle DB 12 ON Radhat Linux 7.7 🔮

Install Oracle DB 12 ON Radhat Linux 7.7 🔮 Oracle Down 기본 설치 사용자, 그룹 생성 Bash profile 커널 설정 Oracle Install 1. 홈페이지 접속 후 원하는 버전의 Oracle DB 다운로드 Oracle DB Download link https://www.oracle.com/database/te
#oracle db#oracle db install#redhat+1
2021-10-14
Spring error : Could not run phased build action using connection to Gradle distribution 해결🌱
blog

Spring error : Could not run phased build action using connection to Gradle distribution 해결🌱

Spring error : Could not run phased build action using connection to Gradle distribution 해결🌱 ■ Error Code Could not run phased build action using connection to Gradle distribution ' https://services.g
#Gradle#java#java spring error+1
2021-09-07
DDU를 사용한 VIDEO TDR ERROR 0x00000116 그래픽카드 충돌 재부팅 문제 해결 🎬
blog

DDU를 사용한 VIDEO TDR ERROR 0x00000116 그래픽카드 충돌 재부팅 문제 해결 🎬

DDU를 사용한 VIDEO TDR ERROR 0x00000116 그래픽카드 충돌 재부팅 문제 해결 🎬 ■ Windows10 OS에서 절전모드 해제 후 자동으로 컴퓨터가 재부팅되는 경우가 발생 분명 절전, 화면보호기 모두 꺼진 상태이지만 일정 시간이 지나면 컴퓨터가 자동 재부팅 되는 현상 확인 1. powercfg 수정 cmd -> powercfg -devi
#ddu#driver#nvidia+4
2021-09-06
Eclipse 원격 저장소 세팅 🌒
blog

Eclipse 원격 저장소 세팅 🌒

Eclipse 원격 저장소 세팅 🌒 Install RSE RUN RSE 이클립스 사용시 원격 서비스를 활용해 접속을 해야하는 경우가 종종 생긴다. 이클립스에서 원격으로 접속하는 방법에 대해서 포스팅하겠다. 1. Remote System Explorer 설치 "eclipse" 실행 후 좌측 상단 "Help" 클릭 이후 "eclipse Marketplace..
#eclipse#eclipse ftp#eclipse sftp+4
2021-09-03
Eclipse error : The project was not built due to "Could not read from source when writing file 🌒
blog

Eclipse error : The project was not built due to "Could not read from source when writing file 🌒

Eclipse error : The project was not built due to "Could not read from source when writing file 🌒 오랜만에 기존의 프로젝트를 빌드하려고 했더니 "The project was not built due to" 에러가 발생한다. 해결 방법은 다음과 같다. Project clean Ecli
#eclipse read error#java error#The project was not built due to
2021-09-03
Start Nessus on Linux - 1 Nessus install 🕵🏻‍♂️
blog

Start Nessus on Linux - 1 Nessus install 🕵🏻‍♂️

Start Nessus on Linux - 1 Nessus install 🕵🏻‍♂️ 1. Download Nessus 2. Install Nessus 성공적인 Penetration Testing을 수행하기 위해서는 먼저 공격 대상의 정보를 수집하는 단계인 Footpringing, Passive Scanning 단계가 이루어져야 한다. 스캐닝을 통한 정보들
#hacking#nessus#nessus install+1
2021-09-02
DNS 주소 변경 이후 Google, Naver 사이트 검색이 안될 때 해결방안 🔎
blog

DNS 주소 변경 이후 Google, Naver 사이트 검색이 안될 때 해결방안 🔎

DNS 주소 변경 이후 Google, Naver 사이트 검색이 안될 때 해결 🔎 DNS 주소를 변경한 이후 검색엔진에서 내 사이트 검색이 안될 때는 기존 설정해 사이트 놓았던 소유권을 갱신해주면 된다. Google Search Console 사이트 갱신 구글 검색 콘솔 접속 https://search.google.com/search-console/about
#DNS#google#google search+3
2021-08-30
dpkg: error processing archive /var/cache/apt/archives/systemd_247.9-1_armhf.deb (--unpack): 해결 ⚙️
blog

dpkg: error processing archive /var/cache/apt/archives/systemd_247.9-1_armhf.deb (--unpack): 해결 ⚙️

dpkg: error processing archive /var/cache/apt/archives/systemd_247.9-1_armhf.deb (--unpack): 해결 ⚙️ ■ linux update 중 rocessing archive 에러 발생 에러 내용 Errors were encountered while processing: /var/cache/a
#--unpack#/var/cache/apt/archives#armhf.deb+1
2021-08-24
/usr/bin/apt-key: 57: cannot create /dev/null: Permission denied 해결 🔐
blog

/usr/bin/apt-key: 57: cannot create /dev/null: Permission denied 해결 🔐

/usr/bin/apt-key: 57: cannot create /dev/null: Permission denied 해결 🔐 ■ apt-get update 명령시 에러 발생 # /usr/bin/apt-key: 57: cannot create /dev/null: Permission denied 에러가 발생되는 /dev/null 시도 # rm -f /dev/n
#/dev/null#apt-get#update
2021-08-24
https setting without cpanel, Wordpresss cpanel without https - 1 📃
blog

https setting without cpanel, Wordpresss cpanel without https - 1 📃

라즈베리파이로 개인 웹서버를 운영하며 Cpanel 없이 HTTPS를 적용한 경험을 정리한다. 실습 중심으로 진행되며, Certbot을 이용한 인증서 발급과 Apache 설정 중심으로 설명한다.
#Certificate#https#linux+3
2021-08-23
https setting without cpanel, wordpresss cpanel without https - 2 📃
blog

https setting without cpanel, wordpresss cpanel without https - 2 📃

https setting without cpanel, wordpresss cpanel without https 2 📃 Install Snapd Install Certbot CertBot 홈페이지 접속 link : https://certbot.eff.org 홈페이지 접속 후 자신의 운영환경을 선택하여 주면 인증서 설치 가이드라인을 제공해준다. 먼저 SSH 접
#certbot#Certificate#https+4
2021-08-23
E: Could not get lock /var/lib/apt/lists/lock. It is held by process 31656 (apt)
blog

E: Could not get lock /var/lib/apt/lists/lock. It is held by process 31656 (apt)

E: Could not get lock /var/lib/apt/lists/lock. It is held by process 31656 (apt) ■ linux update 관련 명령 실행 시 발생하는 에러 E: Could not get lock /var/lib/apt/lists/lock. It is held by process 31656 (apt) 오류가
#apt/lists#error#linux update+1
2021-08-20
Alias 활용
blog

Alias 활용

Alias 활용 Linux OS 에서는 자신만의 명령어를 만들고 활용하기 위해 alias라는 명령어를 사용할 수 있다. alias 를 사용하면 사용자가 정의한 아무리 긴 명령어라도 자신이 알아볼 수 있는 단어나 글자를 입력하여 사용하면 된다. 사용법은 현재 세션에서만 적용하는 방법(재부팅시 삭제), ~/.bashrc 파일을 수정해 현재 접속자에 한해 ali
#alias#linux#update+2
2021-08-18
Could not open file /dev/null, Permission denied, update, upgrade 해결 🔒
blog

Could not open file /dev/null, Permission denied, update, upgrade 해결 🔒

Could not open file /dev/null, Permission denied, update, upgrade 해결 🔒 가끔 리눅스 업데이트를 진행하다보면 이런 오류를 볼 수 있을 것이다. 분명 root 권한으로 업데이트를 쳐줬는데 Permission 에러가 발생한다. 이 문제는 권한이 실제로 올바르지 않았을 때 발생하는 에러이다. 해결방안(root
#/dev/null#permission denied#update+1
2021-08-17
BufferedInputStream + eclipse 인코딩 설정 🧑‍💻
blog

BufferedInputStream + eclipse 인코딩 설정 🧑‍💻

BufferedInputStream + eclipse 인코딩 설정 🧑‍💻 java BufferedInputStream은 컴퓨터의 각 부품 별 성능 격차에 따른 처리 속도 저하를 줄이기 위해서 사용되며, 기존의 처리 방식인 프로그램이 입출력 소스와 직접 작업하는 방법과 달리 중간에 메모리 버퍼와 함께 작업을 진행해 처리 시간을 단축시킬 수 있다. 예제 1 -
#buffer#bufferedinputstream#encoding+1
2021-08-13
SSH 접속자, 파일 전송 ⚡
blog

SSH 접속자, 파일 전송 ⚡

SSH 접속자, 파일 전송 ⚡ ■ 여러가지 상황 속 ssh 프로토콜을 이용한 파일 전송하는 방법 일반적인 상황 # scp "전송할 파일" "목적지 사용자"@"전송할 서버 경로":"저장할 서버의 경로" 기본 SSH 포트가 22번이 아닌 경우 # scp -P "Port 번호" "1234" "전송할 파일" "목적지 사용지"@"저장할 서버의 경로" 디렉토리 전송
#accessor#ssh
2021-08-12
GPG를 활용한 파일 암호화 🔑
blog

GPG를 활용한 파일 암호화 🔑

GPG를 활용한 파일 암호화 🔑 예전에 pgp(GNU privacy Guard)의 오류 때문에 업데이트 에러가 났고 이를 해결하는 방법을 작성한 글이 있었고, gpg에 대해 알아보다 gpg 가 리눅스 운영체제에서 간단하게 특정 파일을 암호화를 지원해주는 기능을 한다는 것을 새롭게 알게 되었다. 이번 글은 리눅스 시스템 기본 탑재 프로그램인 GPG를 이용한
#Encrypt#file encryption#GPG
2021-08-11
TortoiseSVN 2 🐢
blog

TortoiseSVN 2 🐢

TortoiseSVN 2 🐢 지난 포스트에 tortoisesvn 설치, 저장소 등록, 데이터를 저장했었더라면 이번 포스트에서는 등록된 저장소를 외부에서 불러와 데이터를 추가하는 방법을 알아보겠다. 저장소 불러오기 기존에 생성했던 svn 폴더에 정상적으로 데이터가 import 되어 있다. 바탕화면에 저장소를 불러올 새로운 폴더를 생성. 마우스 우클릭 후 SV
#Repository#SVN#Tortoisesvn
2021-08-11
TortoiseSVN 3 🐢
blog

TortoiseSVN 3 🐢

TortoiseSVN 3 🐢 지난 게시글에 tortoisesvn을 사용해 등록된 저장소를 외부에서 불러와 데이터를 Commit 하는 방법에 대해 알아보았고 이어서 CentOS 환경에서 tortoise svn을 사용하는 방법을 알아본다. 가상환경 구축 먼저 기본적으로 가상머신에 ip 할당해주기 위해 간단하게 nmap를 활용해 내가 쓰고 있는 내부 ip만을 확
#Repository#SVN#Tortoisesvn
2021-08-11
Maria DB expert 활용 자동 DB 백업 스크립트
blog

Maria DB expert 활용 자동 DB 백업 스크립트

Maria DB expert 활용 자동 DB 백업 스크립트 WordPress의 자동 백업을 위해 wp-content 와 DB 서버를 구축한 뒤 Crontab Scheduling 작업을 진행하였다. 원활한 Crontab 스케줄링 작업을 위해 Password를 입력 받아야 하는 작업의 자동화 Script를 제작해 보았다. 1. Expert 설치, 설치 확인 P
#BackupScript#expert#Maria DB
2021-08-10
TortoiseSVN 1 🐢
blog

TortoiseSVN 1 🐢

TortoiseSVN 1 🐢 Install SVN Create Repository Add Folder SVN SVN : SubVersion 의 줄임말, 큰 프로젝트에서 버전관리나 소스의 통합과 같은 문제를 해결 하기위해 저장소를 구축하고 버전을 관리한다든지 다양한 문제 발생시 이를 해결하기 위한 Software이다. 단순히 생각하면 Git과 같다고 생각해도
#Repository#SVN#Tortoisesvn
2021-08-10
apt-get update error, GPG Key
blog

apt-get update error, GPG Key

apt-get update error, GPG Key 에러 확인 레포지토리 추가 키 파일 다운로드 해결 php bcmath 설치중 에러가 발생해 /etc/trusted.gpg.d 디렉토리를 삭제해버렸다. 삭제후 업데이트를 진행하다 gpg error 라는 문구가 나타났는데 아마 bcmath 설치 간 설치 경로가 해당 경로로 지정되어서 그 파일만 지울 목적으로
#apt-get#GPG Key#trust.gpg.d+1
2021-08-09
MySQL DB Backup Script 제작, Crontab auto Backup
blog

MySQL DB Backup Script 제작, Crontab auto Backup

MySQL DB Backup Script 제작, Crontab auto Backup 스크립트 제작 스크립트 실행 확인 Crontab 설정 작동 확인 매번 그때그때 mysqldump 명령어를 사용하여 DB와 워드프레스 Content 파일을 백업하는게 힘들어서 간단하게 백업 스크립트를 만들고 crontab에 올리는 방법을 설명하겠다. 스크립트 파일은 각각 백업
#auto#backup#Crontab+3
2021-08-09
The REST API Encountered an error, Your site could not complete a loopback request
blog

The REST API Encountered an error, Your site could not complete a loopback request

The REST API Encountered an error, Your site could not complete a loopback request 몇일 전부터 홈페이지가 너무 느려저서 사이트 점검 플러그인을 받아 실행했다. 아... REST API 요청이 실패했다고 뜬다 아마 밑에 발생한 loopback 에러도 같은 맥락일 듯 싶다. 보통 해당 에러가 발
2021-08-08
특정 DNS 주소로 개인 홈페이지의 접속이 불가능할 때 해결 방안
blog

특정 DNS 주소로 개인 홈페이지의 접속이 불가능할 때 해결 방안

특정 DNS 주소로 개인 홈페이지의 접속이 불가능할 때 해결 방안 현상 확인 해결방법 정상 접속 확인 ■ 개인 홈페이지가 특정 DNS 주소 설정시 접속 불가 현상 발생 취미로 운영하고 있던 개인 홈페이지의 도메인인 jinho.ga가 어느날부턴가 접속이 되지 않는 상황이 발생하였습니다. 평소 외부로 접속할 수 있게 포워딩 작업은 해 놓은 상태이며 특정 접속이
#DNS#freenom
2021-07-07
Linux File 압축 자동 백업 방법
blog

Linux File 압축 자동 백업 방법

Linux File 압축 자동 백업 방법 여유공간 확인 스크립트 작성 실행 권한 부여 ■ Linux File 압축 백업 USB 여유공간 확인 # df -Th 사전에 저장에 사용할 디바이스 ("bigsave-sdb1")는 마운트해 놓은 상태 압축 백업 진행 ■ 파일 백업 종류별 특징 압축 백업 : (tar -czpf) 압축하여 저장, CPU 사용량 증가, 작
#./backup.sh#df#jinho.ga+3
2021-07-07
LibreOffice 사용
blog

LibreOffice 사용

LibreOffice 사용 Libreoffice 설치 Libreoffice 실행 ■ Linux 환경에서의 문서 열람을 위한 LibreOffice 사용 Update Linux # apt-get update -y Libreoffice Install # apt-get install libreoffice 자동 설치 여부를 표시해준다. ■ 실행 libreoffice
#LibreOffice#Linux Office
2021-03-29
NFS 취약점 공격
blog

NFS 취약점 공격

NFS 취약점 공격 NFS 개념 NFS 취약점 공격 SSH 접속 확인 ■ NFS 개념 컴퓨터 사용자의 원격지 컴퓨터에 있는 파일을 자신의 컴퓨터를 사용하는 것처럼 설정 가능하게 해주는 클라이언트/서버형 응용프로그램 ■ NFS 취약점 공격 nfs-utils 설치 # yum install -y nfs-utils "/" Directory NFS 설정 # vim
#NFS#nfs-utils#showmount+1
2021-03-18
Virtualbox Kali Linux 설치 및 한글 설정 방법
blog

Virtualbox Kali Linux 설치 및 한글 설정 방법

Virtualbox Kali Linux 설치 및 한글 설정 방법 다운로드 한글 폰트 다운로드 한글 폰트 적용 로그 확인 폰트 적용 확인 버추얼 박스(Virtualbox) 환경에서 모의 침투 테스트용 운영체제인 칼리리눅스(Kali Linux) 설치방법 및 한글 설정 링크로 다운로드 후 버추얼박스에서 실행 Kali Linux OVA (64bit) - 2021.
2021-03-14
System Log Analysis
blog

System Log Analysis

System Log Analysis - Windows 10 환경 이벤트 로그의 이해 Windows 시스템에는 시스템의 로그가 이벤트 로그형식으로 관리되며, 이벤트 로그를 확인하기 위해서는 Windows 의 이벤트 뷰어를 이용해야 한다. [시작] -> [제어판] -> [관리도구] -> [이벤트 뷰어] Windows 시스템은 응용 프로그램 로그, 보안 로그,
#event log
2021-03-14