웹해킹 공부를 하기 좋은 방법이 여러가지가 있는데, 그 중 하나는 웹해킹 워게임을 푸는 것이라고 생각합니다. 워게임은 해킹관련 문제들을 풀어볼 수 있는 사이트라고 보시면 이해하기 편합니다.


그러한 웹해킹 워게임 사이트 중에서도, SQL Injection이라는 해킹 기법에만 초점을 맞춘 워게임 사이트가 있는데, 통칭 Lord of SQL Injection이라고 불립니다.


해당 사이트 링크는 다음과 같습니다.

https://los.eagle-jump.org/


이 사이트는 Rubiya라고 하시는 분이 제작했다고 알려져 있고 당연한 이야기일 수도 있겠지만 SQL Injection에 관심이 많다고 합니다. (운영은 stypr이라는 분이 한다고 하네요)


Rubiya라고 하는분이 해커스쿨 사이트에 올린 SQL Injection 관련 문서들도 있습니다.


초보자용 문서

http://hackerschool.org/Sub_Html/HS_Posting/?uid=42

전문가용 문서

http://hackerschool.org/Sub_Html/HS_Posting/?uid=43


SQL Injection은 간단하게 설명하자면, 웹 사이트 사용자가 입력한 값이 웹 서버로 가서, 그 값을 토대로 SQL 쿼리문을 만들고, 그 쿼리로 DBMS에 명령을 내립니다. 이때 사용자가 입력한 값이 SQL 쿼리문을 요렇게 저렇게 변형시켜서 웹 사이트 개발자가 의도하지 않은 동작을 하도록 만드는 공격 기법이 SQL Injection이라고 할 수 있습니다.


웹 어플리케이션을 개발해보신 분이라면 좀 더 이해하기 쉽겠지요? 그래서 웹 해킹을 잘하려면 웹 개발에 대하여 잘 알아야 한다는 이야기도 있습니다. 스타트업 회사에서 인턴을 하면서 웹 개발을 1년가까이 해본 저로서는 맞는 이야기라고 생각합니다. 웹 개발 경험이 많이 있거나, 웹 서비스 자체에 대한 이해도가 높을 수록 웹 해킹 기법에 대하여 알게 되었을 때 빨리빨리 습득한다고 생각합니다.


이제 Lord of SQL Injection 사이트에 대해 좀더 알아보겠습니다.


위에 알려진 링크로 이동하시면 다음과 같은 페이지가 나타납니다.



이 사이트는 IE(Internet Explorer: 인터넷 익스플로러)를 지원하지 않는다라는 이야기가 보이네요. 웹 해킹을 하시려면, 아니 웹 개발과 같은 웹 관련된 무언가를 하시려면 필수적으로 크롬 브라우저는 설치하시는 것을 추천합니다. 이유는 다양하게 있겠지만, 웹 표준을 가장 잘 준수하는 웹 브라우저이기도 하고, 성능과 보안측면에서도 뛰어나며, 여러 강력한 확장 프로그램들도 지원합니다. 크롬 브라우저에 내장된 개발자도구 역시 좋습니다.


enter to the dungeon을 눌러서 로그인 페이지를 한번 띄워보겠습니다.

아주 심플한 로그인/회원가입 창이 나타납니다. 이런 워게임 사이트에 가입을 하실 때 어느정도 눈치채신 분도 있겠지만, 일반적인 웹 서비스를 제공하는 사이트에 비해 UX가 몹시 떨어집니다. Join 버튼을 눌렀을 때, 패스워드 확인과 같은 필드가 아예 없는 것을 비롯해서, 비밀번호 찾기 등의 기능도 없습니다. 패스워드의 길이제한이라던지, 특수문자를 몇개를 넣으라던지 같은 제약사항도 없는 경우가 많습니다.


그리고 한가지 더 조언해드리는 바로는 이러한 사이트들은 보통 소위말하는 해커, 정보보안쪽에 관심이 많거나 그쪽 분야에 종사하는 분들이 만든 사이트이고 일반적으로 회원가입한 패스워드가 서버에 암호화되어 저장되지 않을 가능성이 높습니다. 다르게 말하면 여러분들이 가입할때 기입한 패스워드는 사이트 운영자가 그대로 볼 수 있다는 것이지요. 따라서 패스워드는 1234 등과 같이 털려도 상관없는 값으로 하는 것을 추천드립니다.


이렇게 회원가입 후 들어가보도록 합시다.


대충 이러한 페이지가 나타나게 된다. 저기 나타난 몬스터들이 각각 Level의 문제들을 나타내는 것이고, 몬스터 이미지를 클릭하면 해당 문제로 넘어갈 수 있다. 일단 첫번째 저 몬스터를 클릭해서 Level 1을 풀어보겠습니다.


알고리즘 공부를 제대로 해보겠다고 다짐하고난 뒤의 나에게 코드포스는 꽤 괜찮은 공부법인듯 합니다.


온라인 컨테스트가 생각보다 자주 있고, (월 6회정도라고 합니다) 대회형식으로 2시간 집중해서 문제를 풀게 되며, 추후 컨테스트가 끝난 뒤 풀이도 제공합니다. (모든 컨테스트에 대하여 모두 제공하는지는 모르겠습니다.)


또 컨테스트가 끝난 뒤 채점을 하면, 어떤 테스트 케이스에서 틀렸는지, 테스트 케이스 값도 같이 보여줍니다.


알고리즘 공부하기에는 정말 좋은 사이트라고 생각합니다.


A번 문제는 방식을 하나하나 따라가면 되는 시뮬레이션 문제였습니다.


c장의 책을 매일 읽는데 처음에는 v0페이지씩 읽고, 다음날은 v0+a페이지를 읽고, 그다음날은 v0+a+a페이지를 읽고.. 이런식으로 읽는 페이지수에 가속도가 붙다가, 그 읽는 페이지 양의 한계는 v1페이지 입니다.


그리고 다음날 읽을 때는 전날 읽은 페이지 다음부터 읽는것이 아니라 마지막 l페이지 만큼은 다시 복습을 한다고 합니다.


이러할 때 c페이지의 책을 모두 읽는데 걸리는 날 수를 구하는 문제입니다.


아래는 코드입니다.

#include <iostream>

using namespace std;

int main() {
	int c, v0, v1, a, l;
	int current_page = 0;
	int iteration = 0;
	cin >> c >> v0 >> v1 >> a >> l;

	while(true) {
		int increment = v0 + iteration * a;
		if (increment > v1) increment = v1;
		iteration++;
		current_page += increment;
		if (current_page >= c) break;
		current_page -= l;
	}
	cout << iteration << endl;
}


B번 문제는 기하문제인데, 정 n각형에서 각도 a를 구할 때 각 a와 가장 근사한 값을 가진 각도를 나타내는 꼭지점 번호를 구하는 문제입니다.


정 n각형의 그림은 다음 페이지에서 참조했습니다.

https://en.wikipedia.org/wiki/Regular_polygon



그림을 그려보면 n각형에서 나타나는 각도에 패턴이 있는데, 

5각형의 예를 들면, 저기 보이는 검정색 각도(interior angle)이 k라고 하고, 빨간색 각도를 theta라고 한다면


나타날 수 있는 각도는 다음과 같습니다.

v1 v2 v3 = k

v1 v2 v4 = k - theta

v1 v2 v5 = k - theta - theta


n의 수가 커지면 저 k - theta - theta - theta ... - theta 이런식의 경우도 나타나겠죠?


k와 theta는 n에 관한 수식으로 나타낼 수 있습니다.


위 식을 이용해서 적용하면 답을 구할 수 있습니다.


아래는 코드입니다.




#include <iostream>

using namespace std;

double ABS(double x) {
	return x*x;
}

int main() {
	int n, a;
	double k, theta;
	int ans = 3;
	double error = 9999999;
	
	cin >> n >> a;
	k = 180 - (((double)360)/n);
	theta = (((double)180)/n);
	
	double candidate = k;
	error = ABS(candidate - a);
	for (int v3 = 3; v3 <= n; v3++) {
		double cur_err = ABS(candidate - a);
		if (cur_err <= error) {
			ans = v3;
			error = cur_err;
		}
		candidate -= theta;
	}
	cout << "1 2 " << ans << endl;
}


아직은 내공이 부족해서 두 문제 밖에 풀지 못했지만, 꾸준히 풀어서 좀 더 높은 레이팅을 목표로 해보겠습니다.

https://www.acmicpc.net/problem/2670


첫번째 포스팅입니다.


한국정보올림피아드 1996년도 중등부 1번문제 연속부분최대곱 문제를 풀어봤습니다.


흔하디 흔한 dp(dynamic programming)으로 풀었습니다.


dp[i]는 i번째 수열에서 끝나는 부분수열의 최대곱을 저장합니다.


가령 arr이 원래 수열이라고 하면

arr

1.1

0.7 

1.3 

0.9 

1.4 

0.8 

0.7 

1.4 

dp

1.1 

0.77 

1.3 

1.17 

1.638 

1.3104 

0.91728 

1.4 

dp[0]은 arr[0]

dp[1]는 arr[0] * arr[1]

dp[2]은 arr[0] * arr[1] * arr[2]

dp[3]은 arr[0] * arr[1] * arr[2] * arr[3]

dp[4]은 arr[0] * arr[1] * arr[2] * arr[3] * arr[4]

dp[5]은 arr[0] * arr[1] * arr[2] * arr[3] * arr[4] * arr[5]

dp[6]은 arr[0] * arr[1] * arr[2] * arr[3] * arr[4] * arr[5]

dp[7]은 arr[7]

이 됩니다.

dp[7]의 경우를 제외하고 항상 더 곱하는것이 좋은 결과를 가져오는데, dp[6]의 경우 1보다 작으므로, dp[7]에서는 이전 앞의 누적 곱을 제외하고 본인만 가져가는것이 이득이므로 dp[7] = arr[7]이 됩니다.



출력 시, 포맷 스트링으로 %.3lf를 사용하면 소수점 4번째 자리에서 자동 반올림된 값이 나타나는 것을 처음 알았네요.


반올림 된 값으로 출력만 할 경우 유용할 것 같습니다.



#include <vector>
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;

typedef double vt;

int N;
vector<vt> arr;
vector<vt> dp;

int main() {
	cin >> N;
	
	arr.reserve(N);
	dp.reserve(N+1);
	for (int i=0; i < N; i++) {
		vt val;
		cin >> val;
		arr.push_back(val);
	}
	dp[0] = arr[0];
	for (int i=1; i <= N; i++) {
		if (dp[i-1] > 1) {
			dp[i] = dp[i-1] * arr[i];
		} else {
			dp[i] = arr[i];
		}
	}
	vt max_val = -987654321;
	for (int i=0; i < N; i++) {
		max_val = max(max_val, dp[i]);
	}
	printf("%.3lf\n", max_val);
	
}


+ Recent posts