[2025_S2] DreamHack - Dream Beginners

권한·2025년 10월 31일

@Xpert

목록 보기
1/3

#0

Web Hacking : 웹을 대상으로 하는 해킹 (사이트, 하이브리드 웹앱&게임...)
System Hacking(Pwnable) : SW 취약점 찾기
Reverse Engineering : 프로그램을 역으로 분석하여 작동 원리를 알아내는 기술 (SW취약점 파악, 악성 프로그램 행동 분석)

✨ 풀이할 때 생각하면서 할 것
1. 주어진 문제가 어떤 프로그램/서비스인지 이해
2. 취약점이 무엇인지 파악
3. 찾은 취약점을 어떻게 써먹을지 구상
4. 코드/페이로드 작성

#1

진법

한 자릿수에 표현할 수 있는 숫자의 개수. n진수: 0~n-1의 숫자/문자로 표현

  • 2진법(Binary) ; 0, 1 (0b-)
    bit : 0, 1의 조합
  • 10진법 ; 0 ~ 9
  • 16진법(Hexadecimal) ; 0 ~ 9, A ~ F (0x-)
    2진수 4자리를 16진수 한자리로 축약

비트와 바이트

bit : binary digit (8bit = 1byte)
1byte : 282^8 가지의 수 표현가능

💡 최상위 비트(MSB), 최하위 비트(LSB)
최상위 비트 : 이진 데이터에서 가장 왼쪽 비트. Most Significant Bit
▶ 부호가 있는 데이터의 경우 MSB는 부호를 의미.
최하위 비트 : 이진 데이터에서 가장 오른쪽 비트. Least Significant Bit
*Unsigned(부호X)/Signed(부호(O)

바이트 오더링

각 바이트가 메모리에 정렬되는 방식

  • 빅 엔디안 Big Endian
    왼쪽 바이트부터 낮은 주소에 저장. (ex. 네트워크 데이터 전송...)
  • 리틀 엔디안 Little Endian
    오른쪽 바이트부터 낮은 주소에 저장. (ex. 대다수의 PC/서버환경 - Intel x86, x86-64 CPU)

✨비트가 아니라 바이트 오더링. 바이트 내 비트의 순서는 동일하다.

💡 문자열 데이터와 문자열이 아닌 데이터의 메모리 저장

  • 문자열을 메모리에 저장할 때는 바이트 오더링 고려X
  • 문자열이 아닌 데이터는 리틀 엔디안 방식으로 저장

비트 연산

  • 논리 연산

    +x >>> n (논리) : 비트를 n만큼 오른쪽 이동 (음수 부호 유지X)

  • 비트 연산

    +x << n (산술) : 비트를 n만큼 왼쪽 이동 (x를 2n2^n배)
    +x >> n (산술) : 비트를 n만큼 오른쪽 이동, 가장 왼쪽 빈칸은 MSB와 동일 비트로 채움 (x를 1/2n1/2^n배)

비트 연산 활용

  • & 연산 이용한 비트 마스킹
    : 특정 위치의 비트만 표시하거나 가리는 연산
    하위 8비트만 남김 : □(2byte) & 0x00FF
  • & 연산과 시프트 연산 이용한 특정 비트/바이트 가져오기
    하위 1바이트만 가져오기 : □(4byte) & 0x000000FF
    상위 1바이트만 가져오기 : (□(4byte) >> 24) & 0x000000FF
    상위 두번째 바이트 가져오기 : (□(4byte) >> 16) & 0x000000FF
    하위 1바이트의 상위 4비트 가져오기 : (□(4byte) >> 4) & 0x0000000F
  • XOR 연산을 이용한 비교와 암호와
    : 자기자신과 XOR연산하면 0, 같은 값에 2번 XOR연산하면 원래값과 동일

인코딩, 디코딩

인코딩 : 데이터를 특정한 형식으로 변환 (ex.압축)
디코딩 : 원래의(인코딩 전) 값 구하기

  • 아스키 코드(American Standard Code for Information Interchange)
    1byte(7bit 문자, 1bit 오류체크) → 272^7(128)개의 문자 표현 가능
  • 유니코드(Unicode) U+16진수
    최대 32bit로 문자 하나 표현

    인코딩 방식 : UTF - 숫자에서 숫자는 bit의미
    ex. UTF-8은 기본적으로 8bit를 사용, 부족하면 4byte까지 이어붙여서 사용

  • URL 인코딩(퍼센트 인코딩)
    특수문자(:/?#[]@!$&'()*+,;=%공백) 대상, %문자아스키코드16진수로 변환
  • Base64 인코딩
    이진데이터 → 아스키문자 텍스트, 총 64개(알파벳 대소문자, 숫자, +, /)의 아스키 문자 사용

    방법
    1. 6bit씩 묶기, 비트가 6의배수가 아닐 경우 뒤에 0추가
    2. 6bit묶음을 수로 변환, 테이블(표)에서 문자로 치환
    3. 글자수가 4의 배수가 되도록 =을 반복해 뒤에 추가 ; 패딩(Padding)

운영체제(OS)

: 하드웨어 자원(CPU, 메모리, 입출력장치..)을 효율적으로 사용하도록 분배하여 성능 높임

💡 운영체제 종류
-Windows, UNIX(기반 LINUX, macOS, Android, iOS)

(ex.CPU스케줄링, 메모리 공간 분배/사용 과정 관리, 입출력 장치 정보 교환 관리)

커널(kernel)

: 하드웨어 관리 실제로 수행하는 프로그램, 시스템이 부팅될때 메모리에 올라가서 꺼질때까지 실행

셀(shell)

: 사용자와 커널 사이에서 인터페이스 역할, 사용자가 명령을 입력하면 셀이 명령어를 해석하여 커널에 요청
셀을 획득하면 명령어로 원하는 작업 수행/시스템 제어 가능 ▷ 일반적으로 셀을 획득하는 것이 시스템 해킹의 성공

#2

리눅스

  • 셀(shell) : 유저가 리눅스 시스템을 이용할 수 있는 인터페이스
  • 셀 프롬프트 : 셀이 명령어를 입력받을 준비가 되었음 표시

✨ ctrl + alt + t : 터미널 실행, bash셀 자동 실행
✨ 명령어 루트 권한으로 실행 : 명령 맨 앞 sudo

  • sudo apt update : 설치가능한 SW패키지 목록&버전 업데이트
  • sudo apt upgrade : SW패키지 버전 업그레이드
  • id : 현재 유저의 ID와 해당 유저가 속한 그룹ID를 보여줌
  • pwd : Print Working Directory. 현재 작업중인 디렉토리 경로 출력
  • ls : List. 디렉토리 내용 출력. -l 플래그를 추가하면 자세한 정보 출력. 임의 디렉토리 출력도 가능
  • cd : Change Directory.
    - 절대 경로 : 루트 디렉토리 /을 시작으로 모든 경로를 적어서 표현
    - 상대 경로 : 현재 디렉토리를 기준으로 상위/하위로 가는 경로. cd ..은 현재 디렉토리의 부모 디렉토리로 이동.
    - 고유한 경로 : ~ 현재 유저 홈 디렉토리, - 이전에 위치했던 디렉토리
  • cat : 파일 내용 출력. cat 파일경로
  • file : 파일 유형 출력. file 파일경로
  • mkdir : Make Directory. 디렉토리 생성
  • touch : 빈 새 파일 생성
  • vi : vim편집기를 이용한 새파일 만들기, i(Insert)로 내용 입력, ESC > :wq로 빠져나오기

일반 모드(ESC)

- gg : 첫행 이동
- o : 행 처음으로 이동
- G : 마지막 행으로 이동
- i, h, j, k : → ← ↓ ↑
- $ : 행의 끝으로 이동
- x : 현재 커서 위치한 글자 삭제(del)
- X : 현재 커서 앞글자 삭제(backspacce)
- dd : 현재 커서 위치한 행 삭제
- yy : 현재 커서 위치한 행 복사
- p : 복사한 내용 현재 행 이후에 붙여넣기
- P : ,, 이전에 붙여넣기
- /문자열, enter : 현재 커서 이후로 문자열 찾기
- n : 찾은 문자열 목록에서 다음 문자로 이동
- u : 이전 수정 사항 되돌리기

입력 모드(Insert) - 입력은 일반 모드에서

- I : 현재 커서 위치한 행의 처음에 입력 
- s : 현재 커서 한 글자 지우고 입력
- i : 현재 커서 위치에 입력
- a : 현재 커서 다음 칸 입력
- A : 현재 커서 위치 행의 마지막에 입력
- O : 현재 커서 이전 줄에 입력
- S : 현재 커서 한 줄 지우고 입력
- o : 현재 커서 다음 줄에 입력

명령 모드(command)

- :w : 저장
- :q : 종료
- :i : 취소
- :wq : 저장하고 종료
- :q! : 저장하지 않고 종료
- :%s/문자열1/문자열2/g : 전체에서 문자열1을 모두 문자열2로 치환
  • mv : Move. 파일/디렉토리 위치 이동 or 이름 변경
  • rm : Remove. 파일/디렉토리 삭제. 디렉토리는 -r플래그 추가
  • echo : 셀에 유저가 입력한 텍스트 출력. echo "Helloworld"
    + echo 명령문 끝에 > 파일명을 붙이면 입력한 내용을 파일 내용으로 저장
  • cp : Copy. 파일/디렉토리 복사. 디렉토리 복사는 -r플래그 추가
  • grep : 전체에서 특정 문자열 찾기. grep 문자열 파일(경로)
  • man : Manual. 특정 명령어의 메뉴얼 출력
  • curl : client URL. 서버에 데이터를 보내거나 받는 데이터 전송 커맨드. curl [옵션] URL
    - -o file : 전송받은 데이터 파일에 저장
    - -i : 결과값에 HTTP응답 헤더 포함
    - -x method : HTTP 요청 메소드 지정
    - -d "key=value" : HTTP POST 메소드로 데이터 전송

    ✨ 명령어 실행결과를 볼 수 없는 경우 결과를 curl명령어에 포함하여 풀이자의 웹서버로 전속하면 확인 가능

  • 와일드 카드 : 임의의 다른 문자를 나타낼 수 있는 특수 문자
    - ? : a-z, 0-9범위 1개 문자
    - * : a-z, 0-9범위 0개 이상 문자
    - [] : [문자1-문자2] 혹은 [문자1, 문자2..]형태로 범위 지정. 범위 내 모든 문자로 대체 가능 (ex.`ls test[0-9] > test로 시작하고 마지막이 0-9인 파일 모두 출력
  • 리다이렉션redirection : 표준출력/입력을 다른 곳으로 변경. 결과를 파일로 저장 or 다른 명령어의 입력으로 전달
    - 명령어 > 파일 : 명령어 표준 출력을 파일로. 없으면 생성/있으면 덮어쓰기
    - 명령어 >> 파일 : 명령어 > 파일과 동일. but 있으면 이어쓰기
    - 명령어 < 파일 : 명령어 표준 입력을 파일로.
  • 파이프pipe | : 리다이렉션의 한 형태. 명령어 결과 표준 출력을 다른 명령어의 표준 입력으로 보낼 때 사용.

권한

각 유저는 이름과 고유한 사용자ID(UID)를 가짐. 그룹또한 이름과 GID를 가짐

  • /etc/passwd : 유저 정보 저장. 유저 이름/UID/속한 그룹ID
  • /etc/group : 그룹 정보 저장. 그룹 이름/GID/그룹에 속한 유저 목록

파일 & 디렉토리 권한

각 파일과 디렉토리는 소유자owner와 소유그룹을 가지고 있음. 파일/디렉토리의 권한은 ls -l사용

  • Read읽기 r : 내용 보기

  • Write쓰기 w : 수정/삭제 허용

  • Excute실행 x : 파일이 프로그램이라면 실행 허용. 디렉토리라면 내용 접근 허용

  • 권한 플래그 d rwxrwxr-x
    : d 디렉토리 / - 일반 파일 / l 링크파일(바로가기..)
    : d**rwx**rwxrwx : 소유자 권한
    : drwx**rwx**rwx : 소유 그룹에 포함된 유저 권한
    : drwxrwx**rwx** : 나머지 유저 권한

    💡 문자 == 2진수 == 10진수 : rwx == 111 == 7, r-- == 100 == 4
    chmod 764 파일/디렉토리명

  • 소유자 kwonhan
    : 소유자는 파일/디렉토리의 권한 수정 가능

  • 소유 그룹 kwonhan
    : 그룹 단위로 파일/디렉토리에 권한 부여 시 사용

  • chmod : 파일 권한 변경. chmod 권한 파일명 (chmod 764 파일/디렉토리명)
    - chmod g-wx : 그룹 wx권한 빼기, chmod g+r : 그룹 r권한 부여

  • chown : 소유자/소유 그룹 변경. root유저만 가능. chown 사용자명[.그룹명] 파일명

  • chgrp : 소유 그룹만 변경

특수 권한

특수 권한 지정시 권한 플래그 맨 앞에 숫자 붙여서 나타냄. 차례대로 4, 2, 1

  • setuid chmod u+s ~~ : 일반 유저가 파일 실행시 소유자 권한으로 실행. 소유자의 실행 권한x대신 s.
    setuid는 걸려있지만, 실행 권한이 없는 경우 S. chmod **4**755
  • setgid chmod g+s ~~ : 일반 유저가 파일 실행시 소유 그룹 권한으로 실행. setuid와 동일(소유 그룹)
  • sticky bit chmod o+t ~~ : 파일/디렉토리 소유자와 root사용자 외에 일반 사용자가 파일 삭제 불가능.(주로 공용 디렉토리) 일반 사용자의 실행권한 x대신 t. 실행권한이 없으면 T

디렉토리 구조

  • / : 루트 디렉토리(최상위 디렉토리). 절대경로 /
  • /bin : 일반 유저가 사용할 수 있는 기본적인 명령어/프로그램 위치
  • /boot : 시스템 부팅에 필요한 파일 위치
  • /dev : 컴퓨터에 부작된 물리적인 장치들을 디바이스 드라이버를 거쳐 파일 형태로 접근 가능. 장치 나타내는 파일들 위치
  • /etc : 운영체제/운영체제 위에서 동작하는 서비스 설정 파일 위치
  • /home : 각 일반 유저의 홈 디렉토리. /home/kwonhan
  • /lib : 시스템에 필요한 라이브러리 파일 위치. /bin /sbin이 필요로 하는 동적 라이브러리 파일 위치
  • /opt : 소프트웨어 패키지 위치
  • /proc : 리눅스 커널 자원에 접근할 수 있는 파일과 프로세스 나타내는 파일 위치
  • /root : root유저 홈 디렉토리
  • /sbin : /bin과 마찬가지로 기본적인 유저 명령/프로그램 위치. root유저가 사용할 수 있는 프로그램/명령어 가짐
  • /tmp : 유저/프로그램이 임시 파일 생성. 오래 존재했던 파일들은 자동 삭제됨
  • /usr : 사용자 바이너리, 문서, 라이브러리, 헤더 파일 위치
  • /var : 프로그램/시스템이 실시간으로 가변적 파일을 사용/저장 할 때 사용. /var/log의 경우 로그파일 저장

#3

tools

Netcat

현대의 대부분의 네트워크 통신은 네트워크 소켓(통신을 위한 가장 작은 단위의 프로토콜)을 통해 이루어짐.
보안 실습은 서버에서 특정 포트를 통해 서비스를 동작시키는 환경을 구성한다. 이런 경우 클라이언트가 프로그램과 통신하기 위해 사용하는 것이 Netcat.
sudo apt update && sudo apt install netcat 으로 설치할 수 있다.

다운한 버전이 실습 환경과 달라서 netcat-openbsd(최신판) 또는 netcat-traditional(구버전) 중 선택해야한다. +ncat

  • nc hostname(ip) port로 사용 가능.

    nc google.com 80 google.com에 80번 포트로 연결을 요청해서 GET / HTTP/1.1을 입력하면 서버에서 요청에 해당하는 respense를 전송해주는 것을 확인할 수 있다.

웹해킹 문제는 제공되는 http로, 포너블의 경우 nc Host Port로 접속하면 된다.

SSH

Secure (Socket) Shell. 원격 서버(컴퓨터)에 연결할 수 있게 해주는 암호화 된 네트워크 프로토콜
ssh user(접속계정)@HOST(접속하려는 원격서버 도메인/ip) -p(포트접속 옵션)

💡 사용자를 인증하는 방법
1. PW로 인증 (충분한 길이가 아니라면 브루트포스 공격 가능성 위험)
2. 원격 서버에 공개키 저장, 클라이언트 개인키 저장하여 검증. 개인키 파일을 이용하면 -i [개인키 파일 경로] 옵션 이용

코딩

VScode단축키

  • command palette : Ctrl + shift +p
  • terminal : Ctrl + `
    디버깅 F5
  • breakpoint : f9 or 코드번호왼쪽클릭 중단점 설정. 해당 코드 실행 직전에 프로그램 중단.
  • debug view : VARIABLES(변수), WATCH(변수/표현식 결과), CALL STACK(호출한 함수), BREAKPOINTS(설치한 중단점 목록) 등 정보 확인 가능
  • debug toolbar
    - continue/pause : f5. 중단점 만날 때 까지 프로그램 실행/중단
    - step over : f10. 코드 한줄 실행. 함수 만나면 함수 실행
    - step into : f11. 코드 한줄 실행. 함수 만나면 내부로 이동
    - step out : shift + f11. 함수 나머지 부분 모두 실행
    - restart : ctrl + shift + f5. 디버깅 재시작
    - stop : shift + f5. 디버깅 종료

Docker

컨테이너(가상 환경이 구축된 박스)를 만들고, 실행하고, 배포할 수 있는 가상화 플랫폼
VM과 유사하지만 도커 컨테이너는 새로운 운영체제 환경을 구축할 필요 없이 하나의 분리된 프로세스처럼 작동하기 때문에 더 가벼움.

- 도커 이미지 : 도커 컨테이너 전 단계. 컨테이너 생성에 필요한 파일/환경변수/명령어/파일시스템... Dockerfile 작성하고 이미지 빌드해야함. Tag는 버전 지정하기 위해 주로 사용
- 도커 컨테이너 : 도커 이미지로부터 만들어진 인스턴스(=실행중인 이미지). 실행하는 동안 분리된 파일 시스템 사용
- 도커 레지스트리 : 도커 이미지 저장소. Docker Hub

CTF또는 워게임에 Dockerfile이 제공되는 경우 문제 환경 똑같이 재현하여 풀이 가능

도커 명령어

💡 | 은 '또는(or)'을 뜻함

  • docker build : Dockerfile을 이용해 이미지 생성
    - docker build [옵션] <경로>
    - docker build -t <이미지명:태그> <경로> : 이름&태그 지정 기본값 latest
  • docker images : 도커 이미지 목록 출력
  • docker run : 도커 이미지로 컨테이너 생성&실행
    - docker run [옵션] <이미지명|ID> [명령어]
    - docker run **-p** <호스트 PORT>:<컨테이너 PORT> <이미지명|ID> : 포트매핑. 컨테이너에서 리슨하는 포트를 호스트의 특정 포트로 접속할 수 있도록
    - doker run -it <이미지명|ID> <명령어> : 컨테이너에서 bash셸 사용. -i 표준입력 활성화, -t 가상 터미널 사용
    ex) docker run -it my-image:1 /bin/bash : my-image:1로 컨테이너 생성&실행 후 bash셸 열기
    - exit로 컨테이너 종료
  • docker ps : 실행 중인 컨테이너 목록 출력
    - docker ps -a : 종료된 컨테이너까지 모두 출력
  • docker create : 컨테이너 생성만
    - docker create [옵션] <이미지명|ID> [명령어]
  • docker start : (중단된) 컨테이너 시작
    - docker start [옵션] <컨테이너명|ID>
  • docker exec : 실행중인 컨테이너에 접속해 명령 수행
    - docker exec [옵션] <컨테이너명|ID> [명령어] -it옵션으로 bash셸 실행가능
  • docker stop : 실행중인 컨테이너 중단
    - docker stop [옵션] <컨테이너명|ID>
  • docker pull : 레지스트리에 존재하는 도커 이미지 다운
    - `docker pull [옵션] <이미지명>
  • docker rm : 도커 컨테이너 삭제
    - docker rm [옵션] <컨테이너명|ID>
  • docker rmi : 도커 이미지 삭제
    - `docker rmi [옵션] <이미지명|ID>
  • docker inspect : 도커 이미지/컨테이너의 자세한 정보 출력
    - docker inspect [옵션] <이미지or컨테이너명|ID>

Dockerfile

이미지를 생성하는데 필요한 명령어와 모든 설정이 정의된 파일. 도커 이미지를 빌드하기 위해서는 Dockerfile이 필요.

도커 파일의 파일명은 확장자 없이 Dockerfile
docker build를 입력하면 자동으로 이름이 Dockerfile인 파일 찾아 이미지 빌드. -f옵션으로 원하는 이름의 도커 파일 사용 가능. 기본형식은

#주석
명령어 인자
Dockerfile 명령어
  • FROM : 도커 파일 시작 명령어. 생성할 이미지의 기반이 되는 base이미지 저장. 보통 사용할 운영체제 공식 이미지 DockerHub에서 가져옴. FROM 이미지:태그
    FROM ubuntu:18.04
  • ENV : Dockerfile 내에서 사용하는 환경 변수 지정. 파일 내에서 변수는 $변수명 또는 ${변수명}. ENV 변수명 값 or ENV 변수명 = 값
    ENV PYTHON_VERSION 3.11.2
  • RUN : 이미지 빌드시 실행할 명령어. 필요한 패키지 설치/파일권한설정. RUN 명령어 or RUN ["명령어", "인자1", "인자2"]
    RUN apt-get update `RUN ["/bin/bash", "-c", "echo hello"]
  • COPY : src파일/디렉토리를 이미지 파일 시스템의 dest로 복사. COPY <src> <dest>
    COPY . /app
  • ADD : src파일/디렉토리, URL을 이미지 파일 시스템의 dest로 복사 ADD <src> <dest>
  • WORKDIR : Dockerfile내의 명령을 수행할 작업 디렉토리 지정. 리눅스 cd와 유사. WORKDIR 디렉토리(경로)
  • USER : 명령을 수행할 사용자/그룹 지정. USER 사용자명|UID or USER 사용자명|UID[:그룹명|GID]
    USER $username
  • EXPOSE : 컨테이너가 실행중일 때 들어오는 네트워크 트래픽을 리슨할 포트와 프로토콜 지정. TCP(기본)/UDP. EXPOSE 포트 or EXPOSE 포트/프로토콜
    EXPOSE 80/tcp
  • ENTRYPOINT : 컨테이너 실행 시 수행할 명령어 지정. ENTRYPOINT ["명령어", "인자1", "인자2",..]
    ENTRYPOINT ["echo", "hello"]
  • CMD : 컨테이너 실행 시 수행할 명령어 지정 or ENTRYPOINT에 인자 전달. CMD ["명령어", "인자1", "인자2"] or CMD ["인자1", "인자2"]
    CMD ["echo" "hello"]

    💡 Dockerfile내 CMD명령어가 여러개라면 마지막 CMD사용. docker run의 인자를 작성하면 CMD 명령어 무시. ENTRYPOINT가 있는 경우 docker run의 인자가 ENTRYPOINT의 인자가 됨

정규 표현식

: 특정한 패턴(문자 조합을 식으로 나타낸 것)으로 문자열을 표현하는 식. 문자열 내에서 원하는 패턴의 문자열을 찾거나 시환할 때 사용. 정규 표현식에 부합하는 문자열은 정규표현식에 '매치한다'라고 표현
간단하게 특정 형식의 문자열을 표현하고, 형식이 일치하는지 검증 가능(입력값 검증)
'패턴' or /패턴/(/뒤 플래그 작성 가능) 의 형태로 작성 ^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$

정규 표현식 패턴 - 매치

  • 문자/문자열 : 해당 문자/문자열과 매치
  • . : 모든 문자와 매치
  • | : 앞/뒤의 패턴과 매치
  • [] : []안의 문자와 매치
  • [^ ] : ^뒤의 패턴을 제외한 나머지와 매치
  • ^ : 문자열 시작이 특정 패턴인 경우 매치
  • $ : 문자열 이 특정 패턴인 경우 매치
  • \ : \뒤의 특수문자와 매치
  • [a-z], [A-Z], [0-9] : 두 문자 사이 범위의 문자와 매치
  • \w : 알파벳/숫자/_와 매치 ([A-Za-z0-9_])
  • \d : 숫자와 매치 ([0-9])
  • \s : 공백 문자와 매치 ([\b\f\n\r\t\v])

정규 표현식 패턴 - 수량자

기본적으로 탐욕적(greedy) 수량자에 속함(가능한 많은 문자 매치)

  • * : 앞에 나온 문자가 0개 이상이면 매치
  • + : 앞에 나온 문자가 1개 이상이면 매치
  • ? : 앞에 나온 문자가 0개 또는 1개면 매치
  • 수량자? : 게으른 수량자. 최소한의(가능한 적은) 문자 매치
  • {n} : 앞에 나온 문자가 정확히 n개면 매치
  • {n, } : 앞에 나온 문자가 n개 이상이면 매치
  • {n1, n2} : 앞에 나온 문자가 n1개 이상, n2개 이하면 매치

정규 표현식 패턴 - 그룹화

  • () : ()로 감싼 부분을 그룹하하여 하나의 문자처럼 여김

정규 표현식 플래그

/패턴/플래그

  • g : global search. 매치 하는 모든 문자/문자열 검색
  • i : ignore case. 대소문자 구분하지 않고 검색
  • m : multiline. 여러 줄에서 검색
  • s : single line(dotall). 메타문자 .가 개행문자도 포함

정규 표현식의 사용

  • python의 re 모듈
    - re.compile(pattern, flags) : 정규 표현식 패턴 컴파일. 패턴 객체 반환
    - re.search(pattern, string, flags) : 문자열 내에서 패턴 처음 매치하는 문자열 검색. 매치하는 문자열이 있으면 문자열 객체 반환. 없으면 None. 변수명.group()으로 객체에서 매치하는 부분만 반환
    - re.match(pattern, string, flags) : 문자열 시작이 패턴과 매치하는지 검색. 매치하는 문자열이 있으면 문자열 객체 반환. 없으면 None. 변수명.group()으로 객체에서 매치하는 부분만 반환.
    - re.fullmatch(pattern, string, flags) : 전체 문자열이 패턴과 정확하게 일치하는지 확인. 매치하는 문자열이 있으면 문자열 객체 반환. 없으면 None. 변수명.group()으로 객체에서 매치 문자열만 반환
    - re.findall(pattern, string, flags) : 문자열 내에서 패턴에 매치하는 모든 문자열 검색. 모든 매치 문자열을 리스트로 반환. 각 문자열 리스트 인덱스로 접근
    - re.finditer(pattern, string, flags) : 문자열 내에서 패턴에 매치하는 모든 문자열 검색. 모든 문자열 객체(문자열+위치정보) 리스트 형식 반환. group()써야 실제 문자열 얻을 수 있음.

  • python flags
    - i : 인수 - re.I, 인라인(함수식에) - (?i)
    - m : 인수 - re.M, 인라인 - (?m)
    - s : 인수 - re.S, 인라인 - (?s)
    - g : 자동 적용

  • python Raw String
    정규 표현식 내에 \(이스케이프문자)를 쓰면 의도와 달라질 수 있으므로 문자열 앞에 r 붙여서 나타냄. 문자를 그대로 인식

  • JS
    - 정규 표현식 리터럴 사용 : /패턴/ / /패턴/플래그
    - RegExp 객체 생성 : new RegExp(정규표현식 리터럴, '플래그') / new RegExp('패턴', '플래그') * 패턴 입력시 \ 주의
    - pattern.exec(string) : 패턴에 처음으로 매치하는 문자열의 일치 정보 나타내는 결과 배열 반환
    - pattern.test(string) : 패턴에 매치하는 부분 존재시 true 없으면 false 반환
    - string.match(pattern) : 패턴에 매치하는 모든 문자열 배열 형태로 반환. string 위치에는 문자열 저장된 변수 사용

구글링

  • 영어로 검색
  • 알고싶은 내용 뒤에 ctf, write-up등의 단어 추가.
  • 프로그램 실행/설치시 에러로그 그대로 복사하여 검색 > 비슷한 검색 결과가 없으면 개인 환경에 문제점 있을 가능성
  • 반드시 검색 결과에 포함되어야 하는 내용 ""
  • 특정 웹사이트(github.com..) 결과 찾고 싶을 경우 inurl 키워드

Markdown

마크업 언어 : 문서/데이터 구조를 명시하기 위해 사용하는 언어

  • Headings # ~ ###### : (소)제목 설정
  • paragraphs : 줄바꿈 한번은 문단구분X
  • line breaks : 문단이 아닌 줄바꿈 원할 경우 문장 종료 이후 공백 두개
  • text styles : .*, **, ***, ~~
  • blockquotes : > 여러개쓰면 중첩
  • lists : 순서 있는 리스트 num., 순서 없는 리스트 -, *, +
  • codes : `, ```
  • links : [표시할텍스트](링크)
  • images : ![이미지텍스트](이미지경로)
  • escape characters : \

Dreamhack Tools

  • My Request : 접속한 브라우저의 HTTP 요청 정보 상세 출력(IP, Method, Path, QueryString, HTTP요청 헤더&바디...)
  • Request Bin : 랜덤 URL제공, 해당 URL에 사용자 접속 기록 확인 가능 -접속 기록 확인하고 싶은 경우(XSS, CSRF공격 테스트)
  • Cyber Chef : 인코딩/디코딩/암호화/복호화

#4

리버스 엔지니어링 기초

엔지니어링 과정으로 만들어진 프로그램을 역으로 분석하는 것
확장자 : 파일의 종류/용도 나타내는 식별자

  • .msi : 실행파일. Windows Installer 패키지파일, SW설치/배포에 이용
  • .bat : 실행파일. 여러 명령어를 순차적으로 실행할 수 있는 배치 파일. Windows 환경의 자동화 작업 등에 이용

💡 확장자를 바꾼다고 파일의 내용이 달라지는 것은 아님. 어떤 방식으로 사람에게 보여주느냐가 달라지는 것.(사람이 읽을 수 있는 문자가 아닌거지 파일 손상이 아니다.)

💡 HxD편집기
: 파일에 담긴 데이터를 인코딩 없이 데이터를 그대로 확인 가능.

프로그램 이해하기

ChromeSetup.exe를 HxD에디터로 열어보면 첫 4바이트가 4D 5A 78 00이다. HxD에디터의 셋업 exe파일을 확인해 보면 4D 5A 50 00으로 시작한다. 앞의 2바이트가 실행 파일(정확히는 DOS파일)에 대한 헤더의 일부이기 때문이다.

헤더(Header)
: 파일/데이터 구조의 맨 앞부분에 위치하는 데이터. 형식/구조/속성 등에 대한 정보를 담음. Windows실행파일의 경우 4D 5A로 시작하는 MZ헤더가 있다. 앞에서 확인한 바이트중 78 00은 환경이나 프로그램마다 다를 수 있다.

어셈블리어(Assembly)
: 컴퓨터가 실행해야 할 명령어가 데이터, 이 명령어를 기계어

16진수 - 기계어

  • 90 : nop 아무 작업을 하지 않음
  • 48 c7 c0 02 13 00 00 : mov rax, 0x1302 rax라는 저장공간에 0x1302값을 저장
  • 48 83 c3 05 : add rbx, 5
  • 0f 84 ae 00 00 00 : je 0xb4

컴파일
: 사람이 작성한 C수준의 고급 언어를 컴퓨터가 이해할 수 있는 기계어로 변환하여 프로그램으로 만드는 과정

프로그램 만들어 보기

vim을 통해 C언어로 된 파일을 만든다. gcc를 이용해 컴파일하고 프로그램을 실행하면 정상적으로 출력되는 것을 확인할 수 있다.
gcc는 C언어 소스코드를 프로그램으로 변환해주는 컴파일러. -o 뒤의 helloworld라는 이름으로 프로그램이 생성된다.
helloworld 프로그램을 읽어보면 위와 같이 출력된다. xxd는 Window의 HxD편집기와 비슷한 역할을 해준다.
7f 45 4c 46으로 시작한다. 0x45, 0x4x, 0x46은 ASCII코드로 각각 E, L, F

💡 ELF는 Executable and Linkable Format의 약자로 Unix계열 운영체제에서 사용하는 표준 파일 형식이다. Linux에서 exe파일의 역할을 한다.

동적 분석

실행을 통해 동작을 분석하는 것
파일을 다운했는데 권한이 없다.. ls main -l을 사용해 주니 실행권한이 없다.
chmod +x main으로 권한을 주고 시작한다.
pw를 입력하래서 쳐보았더니 너무 짧단다. 하나를 더 늘려줬더니 숫자가 아니라고 한다.
숫자 00000000을 쳐보니 output과 wanted값을 준다. 맞춘 자리는 없다.
보아하니 0이 0xb9를 뜻하는듯 하다.
그렇다면 12345678, 99999999을 입력하면 각 값을 알 수 있지 않을까?
각 숫자의 값은 이렇게 된다.

정적 분석

외적인 관찰만을 통해 정보를 알아내는 것
gidra... 사용. 기계어를 소스코드로 번역해줌

🐥 우분투 환경에 기드라 설치하기
1. https://github.com/NationalSecurityAgency/ghidra/releases 파일을 다운한 후 압축 해제
2. 터미널에서 압축해제 파일로 이동한 후 ./ghidraRun으로 실행

위와 같은 오류가 뜬다면

```
sudo apt update
sudo apt install openjdk-21-jdk
java -version 
[Output] openjdk version "21.0.8" 2025-07-15(21.이상이면 OK)
```

#5

64se64

문제에서 주어진 html 코드를 살펴보면 아래의 이미지와 같이 base64로 인코딩된 값이 있는 것을 확인할 수 있다.
인코딩을 해보면 아래와 같은 python코드를 얻을 수 있다.
얻은 코드를 실행해보면 flag가 얻어진다.

baby-linux

찾아야 할 파일은 flag.txt
파일 리스트를 먼저 뽑아보자.

[Output]
total 24 -rwxr-xr-x 1 root root 884 Apr 21 2023 app.py 
drwxr-xr-x 3 root root 4096 Apr 21 2023 dream 
-rw-r--r-- 1 root root 34 Apr 21 2023 hint.txt 
-rw-r--r-- 1 root root 5 Apr 21 2023 requirements.txt 
drwxr-xr-x 5 root root 4096 Apr 21 2023 static 
drwxr-xr-x 2 root root 4096 Apr 21 2023 templates

hint.txt가 쓸만해 보인다.
읽어주니까 Where is Flag? ./dream/hack/hello라고 출력된다. flag 위치인 듯 하다.
NO! 라고 출력된다..

#!/usr/bin/env python3
import subprocess
from flask import Flask, request, render_template

APP = Flask(__name__)

@APP.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        user_input = request.form.get('user_input')
        cmd = f'echo $({user_input})'
        if 'flag' in cmd:
            return render_template('index.html', result='No!')

        try:
            output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5)
            return render_template('index.html', result=output.decode('utf-8'))
        except subprocess.TimeoutExpired:
            return render_template('index.html', result='Timeout')
        except subprocess.CalledProcessError:
            return render_template('index.html', result='Error')

    return render_template('index.html')

if __name__ == '__main__':
    APP.run(host='0.0.0.0', port=8000)

제공된 코드를 살펴보니 flag라는 단어가 있으면 No라고 출력하는 흐름인가보다.
단어를 대체할 수 있는 와일드카드를 써준다.

flag가 얻어졌다.

Exercise : Welcome-Beginners

nc host1.dreamhack.games 19077을 이용해 서버에 접속하고 Dreamhack을 치면 flag가 얻어진다.

[코드 분석]

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h> //open(), read()
#include <string.h>

#define FLAG_SIZE 0x45

void init() {
	setvbuf(stdin, 0, 2, 0);
	setvbuf(stdout, 0, 2, 0);
}

int main(void) {
    int fd;
    char *flag;

    init();

    // read flag
    flag = (char *)**malloc**(FLAG_SIZE); //char형으로 FLAG_SIZE만큼 메모리 동적 할당. *동적할당 후 free함수로 메모리 회수. X>메모리 누수*
    fd = open("./flag", O_RDONLY);
    read(fd, flag, FLAG_SIZE);

    char cmp_str[10] = "Dreamhack";
    char inp_str[10];   
    printf("Enter \"Dreamhack\" : ");
    scanf("%9s", inp_str);

    if(strcmp(cmp_str, inp_str) == 0){ //매개변수 문자열 비교해서 완전히 같으면 0리턴
        puts("Welcome Beginners!"); //puts() : 문자열만 출력하는 함수
        // print flag
        puts(flag);
    }
    return 0;
}

Exercise: SSH

ssh를 이용해서 서버에 접속을 해준다. 진짜로 연결하겠냐는 질문이 나오는데 yes로 답해주고, pw를 입력해준다.
chall의 계정으로 접속되었다! ls로 파일을 읽어주면 flag라는 파일이 존재한다. 읽어주면 flag를 얻을 수 있다.

Exercise: Docker

도커 빌드 빌드된 이미지로부터 컨테이너 실행. /bin/bash로 bash셸 실행
궁금하니 chall파일을 실행해보고, flag파일을 열면 플래그를 얻을 수 있다.

blue-whale (about 2h)

도커를 먼저 다운해보자.
도커 이미지를 다운 받았으므로 run을 통해 생성/실행 해준다.
도커 이용은 소득이 없는 듯하다...
제공된 도커 파일의 코드를 살펴보니 플래그를 출력하여 파일이름으로 저장하고 삭제해버린다. 음.. 힌트에 있던 dive를 사용해야하는 듯 하다.
그냥 도커처럼 bash셸을 실행하면 되는 줄 알았더니 명령어 자리에 분석할 이미지를 두어야 하나보다.
계속 같은 오류만 뜬다. Docker daemon에 연결할 수 없다는 것 같은데
인터넷을 찾아보니 docker service가 실행이 안되어있다.라는 얘기가 있다. 확인해보니
엥... 잘돌아간다.
재시작을 해보았다. 여전히 제자리인 듯 하다.
연결되지 않는다는게? 분석의 대상이 되는 도커를 말하는건가? 종료하고 나와서? docker ps를 보니 실행되고 있는 도커가 없다.
참고한 페이지에서 소켓에 대한 권한 확인이라는 것을 보아서 바로 확인해 보았다.
앞전에 추가 했기 때문에 이미 docker그룹에 속해있다...
...다운의 문제였나? dive는 이렇게 쓰는게 아닌가?
..아하 dive README를 다시 천천히 읽어보니 Installation이라는 목차가 있었다..
하하 다운이 되었다!
dive dreamhackofficial/blue-whle:1을 입력하면 위와 같은 창을 확인할 수 있다.
Tab을 통해 페이지를 이동할 수 있다. 찾아야 할 부분은 /home/chall 디렉토리로 이동하여 python으로 flag파일을 읽어오는 부분이다.
Contents 창에서 /home디렉토리를 찾아 layer창으로 이동하고 아까 보았던 RUN명령어 위치로 찾아간다. Contents 테이블에서 flag가 뜨는 것을 확인할 수 있다. flag가 끊기는데 Ctrl+p하면 끝까지 나온다.

ex-reg-ex

주어진 코드중 함수 부분만 살펴보면

def index():
    input_val = ""
    if request.method == "POST":
        input_val = request.form.get("input_val", "")
        m = re.match(r'dr\w{5,7}e\d+am@[a-z]{3,7}\.\w+', input_val)
        if m:
            return render_template("index.html", pre_txt=input_val, flag=FLAG)
    return render_template("index.html", pre_txt=input_val, flag='?')

dr로 시작하고 숫자/영문/중 5개이상 7개 이하의 문자가 있어아하며, e뒤에 숫자가 1개이상 오고, am@ 뒤에 소문자가 3이상 7이하의 문자가 있어야하며, .뒤에 숫자/영문/중 하나 이상이 위치해야한다. 가 조건이 되겠다. 조건에 맞는 이메일을 구성해 입력하면 dr_____e1am@aaa.a플래그를 얻을 수 있다.

phpreg

이름/pw를 입력하고 step2로 넘어가 system()함수로 플래그를 찾는 문제다.
일단 제공된 파일부터 보자. step2.php파일을 보면

if (preg_match("/[a-zA-Z]/", $input_pw)) {
  echo "alphabet in the pw :(";
}
else{
  $name = preg_replace("/nyang/i", "", $input_name);
  $pw = preg_replace("/\d*\@\d{2,3}(31)+[^0-8\"]\!/", "d4y0r50ng", $input_pw);

  if ($name === "dnyang0310" && $pw === "d4y0r50ng+1+13") {
    echo '<h4>Step 2 : Almost done...</h4><div class="door_box"><div class="door_black"></div><div class="door"><div class="door_cir"></div></div></div>';

이 코드가 pw 필터링 으로 보인다.
두번째 if문을 보면 name과 pw가 각각 dnyang0310와 d4y0r50ng+1+13인 듯하다.

그대로 입력하니 위의 if문에서 영문 입력을 받지 않는다. 우회를 해야겠다.
php의 str_replace()는 $name에서 $input_name을 받아 /nyang/i를 지워버리고, $pw에서 $INPUT_PW을 받아 /\d*\@\d{2,3}(31)+[^0-8\"]\!/d4y0r50ng 로 치환한다. 하나가 아니라 모두 치환시킨다.
이름은 /nyang/i 에 대한 부분이 지워져도 괜찮도록 입력하면 될테니 dnyanyangng0310으로 입력하고,
pw의 정규 표현식에 맞게 pw를 구성해보면 1@11319!+1+13이 되겠다.
입력하면
거의 다 되었다는 멘트와 커맨드를 입력할수 있는 란이 주어진다.

if ($name === "dnyang0310" && $pw === "d4y0r50ng+1+13") { //name과 pw가 일치하면 if문 안으로 진입
  echo '<h4>Step 2 : Almost done...</h4><div class="door_box"><div class="door_black"></div><div class="door"><div class="door_cir"></div></div></div>';

  $cmd = $_POST["cmd"] ? $_POST["cmd"] : "";

  if ($cmd === "") { //입력이 없으면($cmd가 비어있을때) 출력하는 멘트
    echo '
          <p><form method="post" action="/step2.php">
              <input type="hidden" name="input1" value="'.$input_name.'">
              <input type="hidden" name="input2" value="'.$input_pw.'">
              <input type="text" placeholder="Command" name="cmd">
              <input type="submit" value="제출"><br/><br/>
          </form></p>
    ';
  }
// /flag/i 와 매치하는 문자열이 있으면 Error문자 띄움
  else if (preg_match("/flag/i", $cmd)) { 
    echo "<pre>Error!</pre>";
  }
  else{
    echo "<pre>--Output--\n";
    system($cmd); 
    //system(string $command, [int &$return_value])로 사용한다. 
    echo "</pre>";
  }
}
else{
  echo "Wrong nickname or pw";
}

입력한 값이
flag 문자열이 존재하면 Error가 출력되므로 cat ../dream/fl?g.txt를 입력해주면 flag가 얻어진다.

dreamhack-tools-cyberchef

Rail Fence → Base64 → ROT13 순으로 암호화(인코딩) 했다고 한다.
역순으로 넣어서 복호화(디코딩)해주면 flag를 얻을 수 있다.


개인적인 정리들
도커 설치
VScode-VM연결
공부 방향


출처 - DreamHack beginners

profile
티스토리로 옮김

0개의 댓글