▶ 정규표현식(Regular expression)
프로그래밍에서 문자열을 다룰 때, 문자열의 일정한 패턴을 표현하는 일종의 형식 언어를 말한다. 정규식이라고도 부르며,보통 regex 혹은 regexp라 많이 쓴다. php에서 str_replace 등에서 볼 수 있는 수식이다. 프로그래밍을 배우거나 웹해킹부문에서는 Los나 webhacking.kr을 봤다면 평소에 한번쯤은str_replace 등의 명령어에서 봤을 항목.
▶ 기본 문자
기본적인 문자들만 나열하자면 다음과 같다.
기호 | 설명 |
\d | Any Digit |
\D | Any Non-digit character |
. | Any Character |
\. | Period |
[abc] | Only a,b, or c |
[^abc] | Not a, b, nor c |
[a-z] | Characters a to z |
[0-9] | Numbers 0 to 9 |
\w | Any Alphanumeric character |
\W | Any Non-alphanumeric character |
{m} | m Repetitions |
{m,n} | m to n Repetitions |
* | Zero or more repetitions |
+ | One or more repetitions |
? | Optional character |
\s | Any Whitespace |
\S | Any Non-whitespace character |
^...$ | Starts and ends |
(...) | Capture Group |
(a(bc)) | Capture Sub-group |
(.*) | Capture all |
(abc|def) | Matches abc or def |
이러한 문법 양식에 따라 기본적인 예제들을 풀어보면 다음과 같다.
예제 1) ...\. -> "@@@."와 같은 양식이 된다. 예를 들자면, 'cat.'
예제 2) [cm]an -> "can"혹은 "man"와 같은 양식이 된다.
예제 3) [^c]an -> "@an"와 같이 구성되는 문자 중, @자리에 C를 제외한 문자를 가르킨다. 예를 들자면, "man"
예제 4) [A-C][n-p][a-c] -> regex는 대소문자 구분을 하므로, 첫글자는 A~C중 하나, 두번째 글자는 n~p, 세번째 글자는 a~c로 구성된 것을 가르킨다. 예를 들자면, "Ana", "Bob", "Cpc"
예제 5) waz{3,5}up -> "wazup" 문자 중에서 "z"문자가 3~5회 반복되는 것을 뜻한다. 예를 들자면, "wazzzzzup"
예제 6) aa+b*c+ -> "aa"가 한번 이상 반복되고, "b"가 0번 이상 반복되고, "c"가 한번 이상 반복되는 문자열을 뜻한다. 예를 들자면, "aaaabcc", "aabbbbc", "aacc"
예제 7) \d+ files? found\? -> \d는 아무 숫자, s 문자를 option으로 걸어준 문장이다. 이에 해당하는 문자열의 예시를 들자면, "1 file found?", "2 files found?", "24 files found?"와 같다.
예제 8) \d\.\s+abc -> \s는 space, tab, new line, carriage return 과 같이 일반적인 whitespace 형식을 뜻하는 문자이다. 이에 해당하는 문자열의 예시를 들자면, "1. abc", "2. abc", "3. abc" 가 있겠다.
예제 9) ^Mission: successful$ -> ^와$ 사이에 있는 문자열만 고를 때 사용할 수 있다. 예를 들자면, "Mission: successful"문자열은 고를 수 있겠지만, "Last Mission: unsuccessful"과 같이 되어있다면, 해당 문자열은 고를 수 없다.
예제 10) ^(file.+)\.pdf$ -> 소괄호 안의 그룹을 capture하며, file로 시작하고 끝이.pdf로 끝나는 문자열을 고른다. 예를 들자면, "file_record_transcript.pdf"라는 문자열이 해당 regex에 해당이 되며, "file_record_transcript" 문자열을 capture한다.
예제 11) (\w+ (\d+)) -> alphabet character, 띄어쓰기, digit으로 이루어진 문자열을 가리키며, 소괄호로 Capture되는 그룹은 바깥 소괄호에 해당하는 문자열+숫자, 안쪽 소괄호에 해당하는 숫자 이렇게 두 그룹이 될 것이다. 예를 들자면, "Jan 1987"이라는 문자열에서는 "Jan 1987"문자열 하나와 "1987" 문자열 하나, 이렇게 총 2개의 문자열이 잡힌다.
예제 12) (.*)x(.*) -> 모든 character, "x" 문자, 모든 character 순서로 이루어진 문자열을 잡는다. 예를 들자면, "1280x720"이 있겠다.
예제 13) I love (dogs|cats) -> 소괄호와 파이프 기호 ( | ) 를 쓰면, 논리학적으로 OR의 기능으로 맞는 문자만 가리킨다. 예를 들자면, 예제에 해당하는 문자열은 "I love dogs"와 "I love cats"가 있다.
▶ 정규표현식의 활용
상황 1. 다양한 형태의 십진수 나타내기
^-?\d+(,\d+)*(\.\d+(e\d+)?)?$ -> -를 옵션으로 줘서 음수, 양수 전부 나타낸다.\d문자열 반복 중에 ,\d를 뒤에 올 수 있게 해서 123,340와 같이 천의 자리를 끊어도 읽어낼 수 있게 만들어 준다. 해당 문자열에 *를 걸어줘서 해당 패턴이 있든 말든 고를 수 있게 만들어주고, \.\d+(e\d+)? 는 e로 숫자를 나타낸 1.9e10과 같은 경우를 나타낸다(물론 e와 뒤의 숫자를 옵션으로 줘서 없어도 되니, 소수점도 나타낼 수 있다.). 해당 경우를 전부 option으로 걸어줘서 있든 없든 상관없게 하면 완성된다. 해당 예제의 regex를 시각화하면 다음과 같다.
상황 2. Phone Number 지역번호 잡아내기
1?[\s-]?\(?(\d{3})\)?[\s-]?\d{3}[\s-]?\d{4} -> 1를 option으로 줘서 앞에 1만 붙은 번호도 있으니 이를 반영해준다. 그리고 whitespace와 -가 붙은 부분도 option처리를 해주고, 소괄호로 지역번호를 붙이는 경우도 있으니 소괄호를 escaping해주고 option을 걸어준다. 그리고 이제 시작하는 번호가 Phone Number의 지역번호일테니 소괄호(escaping한 거 말고)로 숫자 3개를 \d{3}으로 잡아준다. 그리고 다시 escaping한 소괄호로 괄호를 닫아주고 이것도 option을 걸어준다. 그리고 마찬가지로 whitespace와 -가 붙은 부분도 option처리를 해주고, 다시 숫자3개를 나타내는 \d{3}을 나타낸다. 그리고 나서 마지막 띄어쓰기로 번호를 표현할 테니, 마찬가지로 whitespace와 - 를 option을 걸어준다. 그리고 마지막 번호 4개를 \d{4}로 나타내면 끝이다. 해당 정규표현식을 시각화하면 다음과 같다.
상황 3. 이메일 아이디 잡아내기
^([\w\.]*) -> alphanumeric number를 잡아내고, @는 alphanumeric 안에 들어가지 않으므로, 무한대로 .를 포함한 문자를 돌려서 해당 문자열을 찾는다. 쉽게말해, @앞의 alphanumeric과 .으로 이루어진 문자를 골라내는 식이다. 그래서 식이 엄청 간단하게 나타난다. 해당 정규표현식을 시각화하면 다음과 같다.
상황 4. HTML 태그명 찾아내기
<(\w+) -> 간단하게 "<" 다음에 HTML태그명이 올 수 밖에 없으니깐, alphanumeric character가 끝날 때 까지 해당 문자를 잡는 Regex이다. 해당 정규표현식을 시각화하면 다음과 같다.
참고로 태그 contents는 >([\w\s]*)< 로 불러올 수 있고, 속성값은 ='([\w://.]*)' 로 잡아낼 수 있다.
상황 5. 특정 파일 확장자의 파일 이름과 확장자 잡아내기 (.jpg, .png, .gif)
(\w+)\.(jpg|png|gif)$ -> alphanumeric character를 소괄호로 잡는데, .(dot)이전까지 잡아낸다. 그리고 뒤에 붙는 확장자가 jpg,png,gif인 경우만 잡아내도록 한다. 마지막에는 반드시 $를 붙여서 마지막 .(dot) 후의 확장자만 잡아낼 수 있도록 한다(확장자는 마지막 태그로 결정되므로, File Upload / LFI 공격이 갑자기 생각났다.). 정규표현식을 시각화하면 다음과 같다.
상황 6. 시작 이전, 끝 이후의 빈칸 잘라내기( = 그 사이부분만 capture하기)
^\s*(.*)\s*$ -> 앞의 모든 white space와 문자열 그리고 뒤의 모든 white space를 가리키는 Regex를 작성한 후, 사이의 부분만 소괄호로 감싸준다. 해당 Regex를 시각화하면 다음과 같다.
상황 7. log file 중에서 정보만 추출하기
(\w+)\(([\w\.]+):(\d+)\) -> 앞에서 alphanumeric character로 시작되는 부분에서 , (, :, ), 기호 사이에 있는 문자를 뽑아내는 Regex식이다. (,:,) 사이에서는 (와 : 사이에서 한번, : 와 ) 사이에서 한번 추출해서 세 개의 alphanumeric character로 이루어진 문자열을 추출하게 된다. 해당 Regex를 시각화하면 다음과 같다.
▶ Webhacking.kr challenge 11
해당 문제는 regex 해석능력만 있으면 5분도 안걸려서 푸는 문제다. 해당 소스코드를 보면..

보면 [1-3][a-f]{5}_.*$_SERVER[REMOTE_ADDR].*\tp\ta\ts\ts 부분에서 Regex형식이 정해지고, 이를 preg_match로 내가 입력한 val값을 Regex식으로 검증해서 True 아니면 False를 반환한다.
각설하고, 설명하자면, [1-3]은 1에서 3중에 하나. [a-f]{5}_는 a에서 f까지의 알파벳 중 하나의 5번 반복 후 _문자 넣어주기, .*는 어떠한 문자열을 넣든말든 상관없다. wildcard를 0번이상 반복하는 문자열을 찾는 것이기 때문이다. 그리고 $_SERVER[REMOTE_ADDR]은 내 IP주소를 구하는 것이니깐, 이는 쉽게 알아서 찾으면 된다. 그리고 Regex를 적용하면 되는데, .(dot)기호는 wildcard 역할을 하니깐, .(dot)위치마다 임의의 문자(나같은 경우는 2)를 넣어주면 된다. 내 IP가 111.111.111.111라고 가정할 때에, 111211121112111와 같이 넣어주면 된다. 마찬가지로, .*는 어떠한 문자열을 넣든말든 상관없고, 뒤에 있는 \tp\ta\ts\ts 부분은 \t 가 tab을 뜻한다는 것을 알면, (tab)p(tab)a(tab)s(tab)s 임은 쉽게 알 수 있다. 참고로 GET방식으로 데이터를 불러오니깐 tab을 url encoding한 값으로 입력해야 하는데, 해당 값은 %09이다.
이제 'val' 파라미터로 정답을 넣으면 클리어 된다. 최종 Payload는 내 IP가 111.111.111.111이라고 가정할 때, 다음과 같다.
https://webhacking.kr/challenge/code-2/?val=1aaaaa_a1112111211121112%09p%09a%09s%09s |

참고로 해당 Regex를 시각화하면 다음과 같다.

출처 : Regex 시각화 - https://regexper.com/
Regex 예제, 활용 - https://regexone.com/
Regex 분석할 수 있는 사이트 - https://regex101.com/
'IT' 카테고리의 다른 글
Assembly x86-64 연습 (0) | 2023.03.27 |
---|---|
Iframe 태그와 sandbox / referrerpolicy (0) | 2023.01.10 |
File Magic Number, File Signature (1) | 2022.12.22 |
[네트워크] IP주소 체계 (0) | 2022.11.08 |
[네트워크] ARP(Address Resolution Protocol)와 홉바이홉 통신 (0) | 2022.11.07 |
댓글