STAGE 7 : Command Injection

 

Command Injection

 

> ServerSide : Command Injection

Command Injection

- Injection (인젝션) : 악의적인 데이터를 프로그램에 입력하여 이를 시스템 명령어, 코드, 데이터베이스 쿼리 등으로 실행되게 하는 기법

- Command Injection : 시스템 명령어에 대한 인젝션; 취약점이 발생하는 원인은 단순하지만, 매우 치명적인 공격으로 이어질 수 있음. 개발자는 이용자의 입력을 반드시 검사해야 하며, 되도록 system 함수의 사용을 자제해야 한다.

- 시스템 함수를 사용하면 이용자의 입력을 소프트웨어의 인자로 전달할 수 있다.

  • 파이썬으로 개발된 웹 애플리케이션에서 입력한 임의 IP에 ping을 전송하고 싶으면 os.system("ping [user-input]")
  • 파이썬으로 개발된 웹 애플리케이션에서 입력한 임의 파일을 읽고 싶다면 os.system("cat [user-input]")

- 위와 같이, 이용자의 입력을 제대로 검사하지 않으면 임의 명령어가 실행될 수 있는데 이는 리눅스 셸 프로그램이 지원하는 다양한 메타 문자 때문이다. 

- && ; | 등을 사용하면 여러개의 명령어를 연속으로 실행시킬 수 있는데 공격자는 이를 이용해 명령어를 실행하여 셸을 획득한다.

 

 

Command Injection 실습

@app.route('/ping')
def ping():
	ip = request.args.get('ip')
	return os.system(f'ping -c 3 {ip}')

- Command Injection이 발생하는 예제 코드

- URL 쿼리를 통해 전달되는 ip값을 ping 명령어의 인자로 전달

 

$ ping -c 3 1.1.1.1; id
$ ping -c 3 1.1.1.1 && id
$ ping -c 3 1.1.1.1 | id

- id 명령어를 실행하기 위해서는 메타문자를 사용해야 한다.

 

 

 

[혼자실습]
Command Injection
#!/usr/bin/env python3
import subprocess

from flask import Flask, request, render_template, redirect

from flag import FLAG

APP = Flask(__name__)


@APP.route('/')
def index():
    return render_template('index.html')


@APP.route('/ping', methods=['GET', 'POST'])
def ping():
    if request.method == 'POST':
        host = request.form.get('host')
        cmd = f'ping -c 3 "{host}"'
        try:
            output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5)
            return render_template('ping_result.html', data=output.decode('utf-8'))
        except subprocess.TimeoutExpired:
            return render_template('ping_result.html', data='Timeout !')
        except subprocess.CalledProcessError:
            return render_template('ping_result.html', data=f'an error occurred while executing the command. -> {cmd}')

    return render_template('ping.html')


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

ping -c 3 "{host}" 에서 {host}는 내가 입력해준 값이 들어간다.

 

ping 페이지 Host 입력칸에 8.8.8.8을 입력해주었더니 아래와 같은 결과가 나왔다.

 

 

아래와 같이 입력값을 주려하는데 "요청한 형식과 일치시키세요."라는 문구가 계속해서 떴다.

 

코드를 살펴보았는데 pattern이 지정되어 있었다.

 

이를 우회하기 위해 burp suite를 사용하기로 했다.

이와 같이 입력하였더니 아래와 같이 ls명령어가 잘 수행되었다. 

flag.py가 있다는 것을 확인했으므로 이를 cat 명령어로 읽어주기로 하였다.

 

burp suite를 이용해 cat 명령어를 사용해주었고 아래와 같이 flag를 획득할 수 있었다.

 

'Web Hacking > Dreamhack' 카테고리의 다른 글

[Dreamhack] Web Hacking STAGE 9  (0) 2022.08.24
[Dreamhack] Web Hacking STAGE 8  (0) 2022.08.18
[Dreamhack] Web Hacking STAGE 6  (0) 2022.08.02
[Dreamhack] Web Hacking STAGE 5  (0) 2022.07.25
[Dreamhack] Web Hacking STAGE 4  (0) 2022.07.19

https://wikidocs.net/22883

 

1) 내부 단어의 학습

- FastText에서는 각 단어는 글자 단위 n-gram의 구성으로 취급한다.

- n을 몇으로 결정하는지에 따라서 단어들이 얼마나 분리되는지 결정된다.

# n = 3인 경우
<ap, app, ppl, ple, le>, <apple>

- 실제 사용할 때는 n의 최소값과 최대값으로 범위를 설정할 수 있는데, 기본값으로 각 3과 6으로 설정되어져 있다.

# n = 3 ~ 6인 경우
<ap, app, ppl, ppl, le>, <app, appl, pple, ple>, <appl, pple>, ..., <apple>

- 단어의 벡터 값 = 내부 단어들의 벡터값 총 합

apple =
<ap + app + ppl + ppl + le>
+
<app + appl + pple + ple>
+
<appl + pple>
+ , ..., +
<apple>

 

2) 모르는 단어 (Out Of Vocabulary, OOV)에 대한 대응

- FastText의 인공 신경망을 학습한 후에는 데이터 셋의 모든 단어의 각 n-gram에 대해서 워드 임베딩 된다.

- 데이터 셋만 충분하다면 내부 단어를 통해 모르는 단어에 대해서도 다른 단어와의 유사도를 계산할 수 있다.

- ex) 'birthplace'란 단어를 'birth', 'place'라는 내부 단어가 있었다면 'birthplace'의 벡터를 얻을 수 있다.

 

3) 단어 집합 내 빈도 수가 적었던 단어(Rare Word)에 대한 대응

- 희귀 단어라도, 단어의 n-gram이 다른 단어의 n-gram과 겹치는 경우라면 비교적 높은 임베딩 벡터값을 얻는다.

- 코퍼스에 오타나 맞춤법이 틀린 단어가 있는 경우, FastText는 이에 대해 일정 수준의 성능을 보인다.

 

 

https://wikidocs.net/33520

 

워드임베딩

- 단어를 벡터로 표현하는 방법

- 단어를 밀집 표현으로 변환

 

원-핫 인코딩 : 단어 집합의 크기를 벡터의 차원으로 하고, 표현하고 싶은 단어의 인덱스에 1의 값을 부여하고, 다른 인덱스에는 0을 부여하는 단어의 벡터 표현 방식

 

1) 희소 표현

- 벡터 또는 행렬의 값이 대부분 0으로 표현되는 방법

- 원-핫 벡터 = 희소 벡터

- 단어의 개수가 늘어나면 벡터의 차원이 한없이 커진다. -> 공간적 낭비

 

2) 밀집 표현

- 희소 표현과 반대되는 표현

- 사용자가 설정한 값으로 모든 단어의 벡터 표현의 차원을 맞춘다.

- 0과 1 뿐 아니라 다른 실수값을 가지게 된다.

 

3) 워드 임베딩

- 단어를 밀집 벡터의 형태로 표현하는 방법

- 임베딩 벡터 : 밀집 벡터를 워드 임베딩 과정을 통해 나온 결과

- 케라스 Embedding() : 단어를 랜덤한 값을 가지는 밀집 벡터로 변환한 뒤에 인공 신경망의 가중치를 학습하는 것과 같은 방식으로 단어 벡터를 학습하는 방법을 사용

https://wikidocs.net/83544

위 내용을 참고하여 정리

 

1) Numpy로 패딩하기

import numpy as np
from tensorflow.keras.preprocessing.text import Tokenizer
preprocessed_sentences = [['barber', 'person'], ['barber', 'good', 'person'], 
['barber', 'huge', 'person'], ['knew', 'secret'], ['secret', 'kept', 'huge', 'secret'], 
['huge', 'secret'], ['barber', 'kept', 'word'], ['barber', 'kept', 'word'], 
['barber', 'kept', 'secret'], ['keeping', 'keeping', 'huge', 'secret', 'driving', 'barber', 'crazy'], 
['barber', 'went', 'huge', 'mountain']]

// 단어 집합을 만들고, 정수 인코딩을 수행
tokenizer = Tokenizer()
tokenizer.fit_on_texts(preprocessed_sentences)
encoded = tokenizer.texts_to_sequences(preprocessed_sentences)
print(encoded)

모든 단어가 고유한 정수로 변환

 

- 모두 동일한 길이로 맞춰주기 위해 가장 길이가 긴 문장의 길이를 계산한다.

max_len = max(len(item) for item in encoded)
print('최대 길이 :',max_len)

최대 길이 : 7

 

- 가장 길이가 긴 문장의 길이는 7이므로 모든 문장의 길이를 7로 맞춘다.  데이터에 특정 값을 채워 데이터 크기를 조정하는 것을 패딩이라고 한다. 숫자 0을 사용하고 있다면 제로 패딩이라고 한다.

for sentence in encoded:
    while len(sentence) < max_len:
        sentence.append(0)

padded_np = np.array(encoded)
padded_np

 

 

2) 케라스 전처리 도구로 패딩하기

케라스에서는 패딩을 위한 pad_sequences()를 제공하고 있다.

padded = pad_sequences(encoded)
padded

 

- pad_sequences는 기본적으로 문서의 앞에 0으로 채우기 때문에 Numpy와의 패딩 결과가 다르다. 뒤에 0을 채우고 싶다면 인자로 padding='post'를 해주면 된다.

padded = pad_sequences(encoded, padding='post')
padded

 

- 꼭 가장 긴 문서의 길이를 기준으로 해야하는 것은 아니다. 길이에 제한을 두고 패딩할 수 있다. maxlen의 인자로 정수를 주면, 해당 정수로 모든 문서의 길이를 동일하게 한다. 길이가 maxlen보다 짧은 문서들은 0으로 패딩되고, 긴 문서는 데이터가 손실된다. 

padded = pad_sequences(encoded, padding='post', maxlen=5)
padded

 

- 기본적으로 앞쪽의 데이터가 손실되는데 뒤의 단어가 삭제되도록 하려면 truncating='post' 를 주면 된다.

 

+ Recent posts