又一次搬家囉! https://blog.inndy.tw

over 6 years ago

最近開始玩某個遊戲的私服,世界各國代理商全倒光之後就有一群人在臺港澳中開了私服,甚至就直接用那個遊戲的名字直接營運.... XD

遊戲主程式有加殼,因為有改過所以沒辦法直接從 section name 或是 exeinfoPE 看出來,後來是 ProtectionId 說他是 VMProtect 2.06(我沒辦法驗證這件事情,基本上他沒開任何 VMProtect 的保護功能)

一開始不知道怎麼脫,x64dbg 配 Win10 的環境也不太好作業,所以就在遊戲跑起來的狀況下 dump memory 然後修 IAT,結果 Win10 因為相容性問題,所以引入了 AcLayers.dll / apphelp.dll ,並且在 PE loader 內去 hook EAT,結果就會讓 Scylla 壞掉


脫殼請在該應用程式支援的最低作業系統版本下進行 XD

總之我就先把這樣的 binary 丟進 IDA 看呀看,後來看到一個 function 在 parse commandline(而且 直接把 GetCommandLineA 為給 sscanf,會 overflow呢 XDDDDD),結果就不小心找到 OEP 了

(VC 編譯出來的 OEP 會是一個 call 緊接著一個 opcode = 0xe9 的 jmp,jmp 的目標裡面會有 GetCommandLineA,接著再往下就會呼叫 WinMain)

後來開了 Windows XP VM,OllyDbg + StrongOD,但是 hardware breakpoint 一直被吃掉,大概是 anti-debug 的功能吧,後來用 PhantOm 也沒辦法處理,後來看到其他 VMP 脫殼都說先 break 在 VirtualProtect (沒辦法,packer 注定要用的 API XDDD),按個幾次 F9 直到看到 protection attribute 是 PAGE_READONLY 為止,現在你的 binary 應該就 decrypt / decompress 完成了,接著去 break OEP,再 F9 就可以 dump 了

接著做出來的 binary 沒辦法執行,會跳 Runtime Error: R6002,查了一下之後在看雪找到解答,Microsoft 的 runtime library 會看某個 section 的 protection attribute,如果可寫就跳過 floating point 相關的 initialization,所以要手動 patch 讓他別跳過(或是也可以設定好正確的 PE section)

最後詳情就請見看雪論壇,照著做patch 完就可以動了!

結論:VMProtection 保護都不開的話基本上脫殼難度只比 asprotect 難一點 XDDDD

看了其他人的分析,在開啟 IAT protection 的狀況下真的很麻煩,不過感覺用 binary instrumentation 的技術去處理 IAT reconstruction 應該蠻有幫助的 XD

 
about 7 years ago

SSH Tunnel 有三種工作模式,使用 ssh tunnnel 的好處有:

  • 在可能被監聽的網路環境保護未加密連線的安全
  • 翻牆
  • 一定程度上取代 VPN,是一個比較 light-weight 的解決方案

先定義兩個名詞:

  • local: ssh client
  • remote: ssh server

在 local listen port A,透過 remote forward 到 host B 的 port C

ssh user@host -L [local_bind_address:]local_port_A:host_B:remote_port_C

example:

ssh user@host -L 8080:10.7.99.8:80 -- 在 local 聽 8080 port,透過 remote 再連到 10.7.99.8:80

在 remote listen port A,透過 local forward 到 host B 的 port C

ssh user@host -R [remote_bind_address:]local_port_A:host_B:remote_port_C

example:

ssh user@host -R 2223:140.112.172.1:23 -- 在 remote 聽 2223 port,透過 local 再連到 telnet protocol 的 ptt

在 local listen port P,建立 socks proxy server

ssh user@host -D [local_bind_address:]local_port_P

example:

ssh user@host -D 7788 -- 在 local 聽 7788 port,會是一個 socks proxy service,連線會透過 remote 再連到目標

 
about 7 years ago

真的很賭爛因為別人的 code 有 bug 讓自己花了超久的時間 debug

最近在寫一個 CTF 訓練平台,架構上採用 peewee + bottle.py 進行開發,因為不想花太多時間去學 Flask 和 Django 這種太龐大的架構(加上有些用法自己不見得喜歡),所以打算自幹整個架構

遇到了一個問題是我需要自訂 view 的路徑,翻了一下 code 之後發現我有 template_lookup 這個 keyword argument 可以用,但是不管怎麼嘗試,就是沒辦法讓 bottle.py 去我指定的 path 找 template file,不知道是不是我對 decorator 有誤解,改了老半天,後來又 trace 了一下 bottle.py 的 code,才發現根本不是我的問題.....

TL;DR

bottle.py(partial)
def template(*args, **kwargs):
    """
    Get a rendered template as a string iterator.
    You can use a name, a filename or a template string as first parameter.
    Template rendering arguments can be passed as dictionaries
    or directly (as keyword arguments).
    """
    tpl = args[0] if args else None
    # should mixin args into kwargs here

    adapter = kwargs.pop('template_adapter', SimpleTemplate)
    lookup = kwargs.pop('template_lookup', TEMPLATE_PATH)  # <-- template_lookup reads from here

    tplid = (id(lookup), tpl)
    if tplid not in TEMPLATES or DEBUG:
        settings = kwargs.pop('template_settings', {})
        if isinstance(tpl, adapter):
            TEMPLATES[tplid] = tpl
            if settings: TEMPLATES[tplid].prepare(**settings)
        elif "\n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl:
            TEMPLATES[tplid] = adapter(source=tpl, lookup=lookup, **settings)
        else:
            TEMPLATES[tplid] = adapter(name=tpl, lookup=lookup, **settings)
    if not TEMPLATES[tplid]:
        abort(500, 'Template (%s) not found' % tpl)
    for dictarg in args[1:]:
        kwargs.update(dictarg)  # <-- my template_lookup appears here

    return TEMPLATES[tplid].render(kwargs)


mako_template = functools.partial(template, template_adapter=MakoTemplate)
cheetah_template = functools.partial(template,
                                     template_adapter=CheetahTemplate)
jinja2_template = functools.partial(template, template_adapter=Jinja2Template)


def view(tpl_name, **defaults):
    """ Decorator: renders a template for a handler.
        The handler can control its behavior like that:

          - return a dict of template vars to fill out the template
          - return something other than a dict and the view decorator will not
            process the template, but return the handler result as is.
            This includes returning a HTTPResponse(dict) to get,
            for instance, JSON with autojson or other castfilters.
    """

    def decorator(func):

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            result = func(*args, **kwargs)
            if isinstance(result, (dict, DictMixin)):
                tplvars = defaults.copy()
                tplvars.update(result)
                return template(tpl_name, **tplvars)
            elif result is None:
                return template(tpl_name, defaults)  # <-- if goes here

            return result

        return wrapper

    return decorator

Patch at here and PR at here

 
over 7 years ago

一般人聽到 CTF 可能會有的反應大概就幾種:「那是什麼?」、「駭客的遊戲?聽起來好可怕」、「蛤?」,加上一個人打 CTF 太孤單,所以來寫這篇文章,向大家介紹 CTF!

所以 CTF 到底是殺小?

Capture The Flag,駭客的搶旗遊戲,Flag 通常就是一串文字,或是要達成指定的目標。

至於這個 Flag 要怎麼拿呢?基本上主辦方會架設一些有漏洞的服務系統,或者是含有漏洞的程式,又或者是把資訊隱藏在檔案裡面,挑戰者要想辦法用駭客攻擊的手法入侵系統,或者想辦法找出或解密藏在檔案或程式內隱藏的 Flag

CTF 的賽制

基本上可以分成四種:

Jeopardy

Jeopardy 會有多道題目可以解,題目常見類型如下:

misc

綜合題,什麼都有可能,雜七雜八無法分類通常就會算成這個

pwn

目標通常會是一個服務,有漏洞可以打下來,(大多時候)會給你那個 service 的 binary

bin (revsersing)

就是需要逆向工程,不限於執行檔,也遇過各種奇怪的檔案格式

web

就是 Web 啊,不解釋(?)

題型不出幾種:SQL Injection / Command Injection / Cookie / Race Condition,但是思考要很猥瑣才有辦法解題

crypto

密碼學啊不解釋(?)

  • RSA 是常考題,在 MMA CTC 2015 看到了 ECC....
  • AES 也常常出現
  • 各種奇怪的弱 cipher
  • 頻率分析
  • xor

stego

猜謎!猜謎!猜謎!

有些低品質的 CTF 根本就是在玩猜謎,所有題目有一大半都是 stego 也是有可能的

每一道題目解開都可以拿到一組 Flag ,輸入記分板之後可以換分數!
以上就是關於 Jeopardy 的介紹

Attack & Defense

每一組參賽者要維護一台主機,主機上面會跑多個服務,這些服務是由主辦方設計的,每個都含有漏洞,並且在主機上會放置有Flag,這組Flag會在每個回合由主辦發更新一次。

比賽方式

  • 入侵其他參賽者維護的主機,偷取Flag
  • 修補自己主機上的漏洞,防止其他參賽者偷取你的Flag
  • 把對手的Flag遞交到主辦單位的記分板就可以獲得額外分數
  • 如果成功守護自己的Flag也會有分數
  • 如果自己的Flag被偷走則拿不到分數

這樣的比賽模式相較 Jeopardy ,更為接近真實的攻防環境

King of the Hill

跟 Attack & Defense 有點類似,不過每個隊伍一開始不會擁有主機,而要把主辦方提供的主機打下來然後寫入自己的Flag(例如:改首頁),參賽者要守護已經打下來的主機,不被其他隊伍搶走,每個回合依照擁有主機的數量進行加分。

比起 Attack & Defense ,這是企業每天都真實上演,每天都要面對的狀況,更能模擬和考驗駭客在戰場上的實力

CGC

前陣子由美國國防部下屬單位(DARPA)主辦的 CTF 競賽,可以算是 Attack & Defense 的一種,但是多了一條規定,不可以由人類進行攻擊或修補漏洞,攻擊和修補必須寫程式來自動進行,人腦處理資訊的速度有限,但是電腦很快,把事情交給電腦作會是未來的發展方向

所以我說那個 CTF 戰隊呢?

台灣有不少實力堅強的戰隊、組織在打 CTF ,像是 台大217Lab、HackStuff、BambooFox ...等,都有好手齊聚一堂一起比賽,以前偶爾會跟 HackStuff 一起打比賽,後來比較少聯絡,這些隊伍都很厲害也很頂尖,但是也就只有這幾個隊伍上的了檯面,加上台科和TDoH的戰力都不太夠,而且強大的隊伍都已經夠強大了,加上一個人打CTF實在太無力,又難以拿下名次,所以打算成立一個CTF戰隊來培養實力,尋找戰友!

 _____ ___  ____  __  __   ____ _____ _____   _____ _____    _    __  __
|  ___/ _ \|  _ \ \ \/ /  / ___|_   _|  ___| |_   _| ____|  / \  |  \/  |
| |_ | | | | |_) | \  /  | |     | | | |_      | | |  _|   / _ \ | |\/| |
|  _|| |_| |  _ <  /  \  | |___  | | |  _|     | | | |___ / ___ \| |  | |
|_|   \___/|_| \_\/_/\_\  \____| |_| |_|       |_| |_____/_/   \_\_|  |_|

  ___           _             ___  __   __
 / __|___ _ __ / |_ _  __ _  | __|/  \ /  \ _ _
| (__/ _ \ '  \| | ' \/ _` | |__ \ () | () | ' \ _ _ _ _
 \___\___/_|_|_|_|_||_\__, | |___/\__/ \__/|_||_(_|_|_|_)
                      |___/
 
over 7 years ago

Use built-in http module and ecstatic for middleware.

First, install ecstatic

npm install ecstatic

And the magic!

serve.js
var http = require('http'),
    ecstatic = require('ecstatic');

http.createServer(ecstatic({root:'./'}))
    .listen(8080, '127.0.0.1');
 
almost 8 years ago

某網站小遊戲加密弱點分析

故事是這樣的,某(N)(T)(U)的某系之夜弄了一個網站,上面有幾個 JS + canvas 寫的小遊戲,看到小遊戲我怎麼能夠放過不玩(弄)呢?

先來看看原始 Code

Encode.js
function Encode_orig(t, n) {
    var i = 'abcdefghijklmnopqrstuvwxyz0123456789{:}"!@.$%,&*()_+ABCDEFGHIJKLMNOPQRSTUVWXYZ?',
        o = {},
        e = i.length;
    n %= e, 0 == n && (n = 2);
    for (var r = 0; e > r; r++) o[i[r]] = r;
    for (var s = t.split("").map(function(t) {
        return o[t]
    }), r = 0; r < s.length; r++) s[r] = s[r] * n % e;
    return s.map(function(t) {
        return i[t]
    }).join("")
}

存在問題

  1. map 上的第一個 char 不會被換置
  2. 完全對稱加密
  3. key == 1 時,等於原文
  4. key 空間太小(key %= char_map.length),使得 bruteforce 可能
function Encode(str, key) {
    // the map

    var char_map = 'abcdefghijklmnopqrstuvwxyz0123456789{:}"!@.$%,&*()_+ABCDEFGHIJKLMNOPQRSTUVWXYZ?';

    key %= char_map.length;

    if (key == 0) {
        key = 2;
    }

    return str.split("").map(function(e) {
        return char_map.indexOf(e);
    }).map(function (e) {
        return e * key % char_map.length;
    }).map(function(e) {
        return char_map[e]
    }).join("");
}

function Decode(str, key) {
    var char_map = 'abcdefghijklmnopqrstuvwxyz0123456789{:}"!@.$%,&*()_+ABCDEFGHIJKLMNOPQRSTUVWXYZ?';
    var rev_map = Encode(char_map, key);

    return str.split("").map(function(e) {
        return char_map[rev_map.indexOf(e)];
    }).join("");
}

function Bruteforce(str, filter) {
    var r = [];
    for (var i = 2; i < 80; i++) {
        var c = Decode(str, i);
        if (!filter || filter(c)) r.push([i, c]);
    }
    return r;
}

var r = Bruteforce('0pq}SpXpd1YnbYnb9Sbn}t$}Kp,', function (e) {
    // JSON data must starts with '{' or '['

    return e[0] == '{' || e[0] == '[';
});

console.log('Bruteforce result:\n' + r.join('\n') + '\n');

var key = 12345;
var enc = Encode('abcdefghijklmnopqrstuvwxyz0123456789{:}"!@.$%,&*()_+ABCDEFGHIJKLMNOPQRSTUVWXYZ?', key);
var dec = Decode(enc, key);
console.log("Key: " + key);
console.log("Encoded: " + enc);
console.log("Decoded: " + dec);


function validate() {
    var test_str = [ 'abcdefg', 'asjdfjaklsdf', 'jqjriowjoiasjdf', 'abcdefghijklmnopqrstuvwxyz0123456789{:}"!@.$%,&*()_+ABCDEFGHIJKLMNOPQRSTUVWXYZ?', 'owoasdf123______________' ];
    var test_key = [ 1234567, 223457, 123456789, 12343412, 333333334, 2345, 2, 0 ];
    var result = true;

    test_str.map(function (qq) {
        test_key.map(function (pp) {
            result = result && ( Encode(qq, pp) === Encode_orig(qq, pp) );
        });
    });

    return result;
}

console.log();
console.log('Testing my implement...');
console.log(validate() ? "Test pass" : "Test failed");

改進建議

  1. 使用現有 cryptology library
  2. 加強混淆強度
  3. 這幾個小遊戲真的不太好玩
 
almost 8 years ago

SQL Injection 是怎麼發生的?

這篇文章原本是要寫給學校的老師看的,覺得可以拿來資安科普所以就貼到 Blog 吧!

首先,考慮以下 PHP 程式碼

<?php
function login($user, $pass) {
    $sql = "SELECT * FROM `users` WHERE `name` = '$user' AND `password` = SHA1('$pass')";
    $user = query($sql);
    if (count($user) > 0)
        return $user[0];
    else
        return false;
}

$user = login($_POST['user'], $_POST['pass']);
if ($user !== false)
    echo "登入成功:" . $user['name'];
else
    echo "登入失敗!";

使用者輸入資料:

user=%27%20or%20%27%27%20%3D%20%27%27%20--&pass=aaaaaaa

解碼後(--# 是 SQL 註解)

user -> ' or '' = '' -- , pass -> aaaaaaa

進入 PHP 組合成 SQL 語句

SELECT * FROM `users` WHERE `name` = '$user' AND `password` = SHA1('$pass')

帶入資料後

SELECT * FROM `users` WHERE `name` = '' or '' = '' --' AND `password` = SHA1('aaaaaaa')

由於 ' or '' = '' -- 造成一個永遠成立 (某些條件 or True),就可以繞過驗證登入

另外一些技巧,如:

SELECT * FROM `topics` WHERE `id` = '$id'

帶入

$id = -1' UNION SELECT * FROM users --

組合後

SELECT * FROM `topics` WHERE `id` = '-1' UNION SELECT * FROM users --'

會造成 id = -1 不存在,select不出任何東西,但是 union select 會撈出別的資料

除此之外,就算是 checkbox, select, radio 都有可能修改其 value,所以只要是從 user 出來的資料,一律要經過過濾

推薦閱讀文章:如何正確的取得使用者 IP? (Devcore) (使用者 IP、User-Agent 可以竄改)

 
about 8 years ago

身為一個網管,平常的好(ㄜˋ)習(ㄑㄩˋ)慣(ㄨㄟˋ)之一就是看Log
定期看看你的 server 最近又被誰踹了、有哪些攻擊的痕跡、有誰跟你 Say Hello (?

HTTP Access Log

User-Agent

$ log-cat.py "{8}" school-access.log | sort | uniq -c | sort -nr | head -n 16
  56428 -
   2716 Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.15) Gecko/2009102815 Ubuntu/9.04 (jaunty) Firefox/3.0.15
   2569 Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36
   2206 Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.91 Safari/537.36
   2175 Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:37.0) Gecko/20100101 Firefox/37.0
   1444 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7
   1031 Apache/2.4.7 (Ubuntu) PHP/5.5.9-1ubuntu4.5 (internal dummy connection)
    895 Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
    698 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:34.0) Gecko/20100101 Firefox/34.0
    590 Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)
    584 Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)
    508 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
    491 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:35.0) Gecko/20100101 Firefox/35.0
    451 Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0
    431 Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
    407 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.91 Safari/537.36
Read on →
 
about 8 years ago

Garena 被駭事件玩家事後處理建議

發生了什麼事?

Garena 遊戲公司遭到惡意入侵,旗下兩款遊戲「Path of Exile 流亡黯道」以及「League of Legends 英雄聯盟」安裝程式被植入惡意程式(PlugX

是誰幹的?

據目前了解,一個被命名為 Winnti Group 的組織所為,他們在過去曾經攻擊上百個遊戲公司,竊取遊戲原始碼、在遊戲檔案植入惡意程式、竊取使用者密碼等行為

我是不是受害者?

過去四個月內(2014年九月 ~ 2014年十二月)曾經下載並安裝「Path of Exile 流亡黯道」以及「League of Legends 英雄聯盟」者,您很有可能是受害者

此外,您可以檢查電腦是否存在以下兩個檔案,若有出現,您極為有可能是受害者

C:\Windows\System32\NtUserEX.dll
C:\Windows\System32\NtUserEX.dat

我該怎麼辦?

  1. 使用趨勢科技推出的解毒程式進行處理
  2. 立刻安裝防毒軟體進行全面掃描
  3. 若您的密碼曾經與 Garena 遊戲公司註冊帳號重複使用者,請立即更改密碼(特別注意 E-mail 與 Facebook 帳號的安全)

附錄

哪裡有好用的免費防毒軟體?

HITCON Freetalk -- OperationGG

影片在這裡

結語

請各位遊戲玩家保持警覺,如果防毒軟體說遊戲有毒也請謹慎處理,可將疑似出問題的檔案上傳至 VirusTotal 掃描評估,重要的服務、網站系統請使用不同的密碼(E-mail、Facebook),並且請保持您的電腦所有軟體都有隨時更新,停止使用終止支援的作業系統(例如:Windows XP)、軟體,以保護自身設備的安全。

以上是小弟在HITCON Freetalk現場寫的廢文,最後祝各位玩家遊戲愉快!

 
over 8 years ago

WebGoat installing instruction

you can run this tutorial under any debian family distro but not other platform

  1. sudo apt-get install tomcat7 tomcat7-admin
  2. sudoedit /etc/tomcat7/tomcat-users.xml
  3. edit tomcat-users.xml like below
  4. sudo service tomcat7 force-reload
  5. open http://your-server.net:8080/manager/html and upload your war file
  6. open http://your-server.net:8080/WebGoat-X.X and enjoy your hack. (admin interface will show the path)

tomcat-users.xml configure example

tomcat-users.xml should looks like below

tomcat-users.xml
<?xml version='1.0' encoding='utf-8'?>
<!--
  ...
-->
<tomcat-users>
<!--
  ...
-->
  <role rolename="manager-gui"/>
  <user username="admin" password="admin" roles="tomcat,admin-gui,manager-gui,webgoat_user,webgoat_admin"/>
  <user username="guest" password="guest" roles="tomcat,webgoat_user,guest"/>
</tomcat-users>
 
over 8 years ago

最近發現有 ht editor ,於是想下載編譯來用
無奈奮鬥了半小時還是搞不定,差點就放棄直接載 sourceforge 上的 binary 來用,所幸最後還是搞定了

compile.sh
# if you are not use debian family, install dependency on your own

sudo apt-get install autoconf automake libncurses-dev texinfo byacc flex
git clone --depth 1 https://github.com/sebastianbiallas/ht.git
cd ht
./autogen.sh
./configure
make
make htdoc.h
make
sudo make install
 
over 8 years ago

今天被問了奇怪的問題,覺得有價值筆記下來,VBA不解釋

split-sheets-to-files.vbs
Sub Main()
    If MsgBox("Hi, Split sheets to files?", vbYesNo) = vbNo Then Exit Sub
    Dim xPath As String
    xPath = Application.ActiveWorkbook.Path
    Application.ScreenUpdating = False
    Application.DisplayAlerts = False
    For Each xWs In ThisWorkbook.Sheets
        xWs.Copy
        Application.ActiveWorkbook.SaveAs Filename:=xPath & "\" & xWs.Name & ".xls"
        Application.ActiveWorkbook.Close False
    Next
    Application.DisplayAlerts = True
    Application.ScreenUpdating = True
    MsgBox "Done! Files are in..." & vbNewLine & Application.ActiveWorkbook.Path
End Sub
 
over 8 years ago

有在用VIM的人應該會覺得ESC好遠好難按,Caps Lock根本用不到
或是emacs的使用者應該會覺得Ctrl的位置很不方便
這時候我們就可以把Caps Lock改成ESC或是Ctrl

對於X Window環境我們可以直接用 xmodmap 來解決,至於Mac OS X則要透過Seil這個軟體來解決

X Window

xmodmap -e "keycode 66 = Escape NoSymbol Escape"

Mac OS X

Seil ( https://pqrs.org/osx/karabiner/seil.html.en )

 
over 8 years ago
crackme_main.c
int __cdecl main() // decompiled with IDA
{
  char *char_ptr; // edi@2
  int val_1; // eax@3
  int val_tmp_1; // edx@3
  char val_tmp_2; // zf@4
  int length; // edi@8
  unsigned int counter_1; // eax@9
  unsigned __int8 v6; // dl@9
  signed int counter_2; // eax@14
  unsigned __int8 table_2[8]; // [sp+18h] [bp-824h]@1
  unsigned int __table_2_2; // [sp+1Ch] [bp-820h]@1
  unsigned __int8 table_1[24]; // [sp+20h] [bp-81Ch]@1
  unsigned int __table_1_2; // [sp+24h] [bp-818h]@1
  unsigned int __table_2_3; // [sp+28h] [bp-814h]@1
  unsigned int __table_2_4; // [sp+2Ch] [bp-810h]@1
  char process_buffer[1024]; // [sp+30h] [bp-80Ch]@11
  char input_buffer[1036]; // [sp+430h] [bp-40Ch]@2

  sub_401C30();
  /*
    unsigned char map_1[] = {
        0x10, 0x7D, 0x33, 0xCE, 0x30, 0xF7, 0x88, 0x3C,
        0x23, 0x02, 0x73, 0xC2, 0x3D, 0xDF, 0xF2, 0x5E
    };
    unsigned char map_2[] = { 0x65, 0x13, 0x00, 0xB8, 0x03, 0xC5, 0xE6, 0x0C };
  */
  
  *(_DWORD *)table_1 = 0xCE337D10u;
  __table_1_2 = 0x3C88F730u;
  __table_2_3 = 0xC2730223u;
  __table_2_4 = 0x5EF2DF3Du;
  *(_DWORD *)table_2 = 0xB8001365u;
  __table_2_2 = 0xCE6C503u;
  while ( 1 )
  {
    char_ptr = input_buffer;
    printf("Enter key to unlock: ");
    fgets(input_buffer, 1024, (FILE *)iob /* stdin */);
    
    do {
      val_tmp_1 = *(_DWORD *)char_ptr;
      char_ptr += 4;
      
      // 這個地方有點特別可以算算看
      // unsigned char b = 0x00;
      // ~b & (b - 0x01) & 0x80 == 0x80
      // 等價於 b ? 0x00 : 0x80
      // 推廣到int32_t
      val_1 = ~val_tmp_1 & (val_tmp_1 - 0x1010101) & 0x80808080;
    } while ( !val_1 );
    
    // 判斷low-part有沒有東西
    val_tmp_2 = (unsigned __int16)(val_1 & 0x8080) == 0;
    
    if ( !(val_1 & 0x8080) ) // 如果low-part有東西的話,把hi-part拉到low-part,讓後面繼續判斷
      val_1 = (unsigned int)val_1 >> 16;
      
    if ( val_tmp_2 ) // 如果low-part有東西的話 +2
      char_ptr += 2;
      
    // 最後其實就是strlen
    length = &char_ptr[-((_BYTE)val_1 >= (unsigned __int8)-(_BYTE)val_1) - 3] - input_buffer - 1;
    
    // 基本上這是個無意義操作
    input_buffer[length] = 0;
    
    if ( length > 0 )
    {
      v6 = 0x10; // 注意囉,first byte的xor key是 0x10
      // 底下看起來很可怕,而且一次 shift 59 bits有點奇怪,背後的 opcode 是:
      // 00403832 sar     ecx, 31
      // 00403835 shr     ecx, 28
      // 這裡先說明一下 sar 這個指令, SAR (Shift Arithmetic Right)
      // 基本上他做的事情是shift right (shr),但是他會用MSB做填充,即正負不變
      // 用於 signed 操作,至於 shr 則是 shitft right ,空位用 0 填充
      // sar reg, 31 是有特殊意義的,他會用MSB填滿整個register,
      // i.e.: reg = (reg < 0) ? -1 : 0;
      // 接下來的 shr ecx, 28 ,串起來就會變成 reg = (reg < 0) ? 0b01111 : 0;
      // 這時候 & 0x0F 就變成沒有意義的操作了
      // 所以可以化簡成 ((counter_1 + (counter_1 >> 59))) - (counter_1 >> 59)
      // counter_1 + (counter_1 >> 59) - (counter_1 >> 59)
      // 最後就變成 v6 = table_1[counter_1]
      for ( counter_1 = 0; ; v6 = table_1[((counter_1 + (counter_1 >> 59)) & 0xF) - (counter_1 >> 59)] )
      {
        process_buffer[counter_1] = input_buffer[counter_1] ^ v6;
        ++counter_1;
        if ( length == counter_1 )
          break;
      }
      // first byte 是分開處理的
      // first byte = 'e' ^ 0x10 = 'u'
      // 另外由此可知,key length 是 8
      if ( length == 8 && process_buffer[0] == 'e' )
        break; // 這個 break 會出 最外層的 while ( 1 ),就會跳過LABEL_18
    }
LABEL_18:
    puts("Key error, please retry :)");
  }
  counter_2 = 0;
  while ( 1 )
  {
    ++counter_2; // minium counter_2 is 1
    if ( counter_2 > 7 ) // counter_2 -> [1, 7]
      break;
    // counter_2 永遠小於等於 7 ,所以 & 7 也是無意義操作
    // 所以可以知道 input 會先跟 table_1 做 xor 在跟 table_2 比對
    // key[1] ~ key[7] 就是 table_1[i] ^ table_2[i] , i -> [1, 7]
    if ( process_buffer[counter_2] != table_2[counter_2 & 7] )
      goto LABEL_18;
  }
  puts("Successfully unlock!");
  system("pause");
  return 0;
}

Key is un3v32n0

Reference: Intel Pentium Instruction Set Reference (Basic Architecture Overview)

 
almost 9 years ago
iptables-setup.sh
#!/bin/bash


if [ $UID -ne 0 ]; then
    sudo $0 $*
    exit
fi

# Clear default rules

iptables -F
iptables -X
iptables -Z

# Default policy for INPUT

iptables -P INPUT DROP

# Accept for loopback

iptables -A INPUT -i lo -j ACCEPT

# Allow ssh, http

iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 8000 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT

# Do not drop packet from established connection

iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# List

iptables -L -n -v
sudo cp iptables-setup.sh /etc/init.d/
sudo chown root:root /etc/init.d/iptables-setup.sh
sudo chmod 755 /etc/init.d/iptables-setup.sh

# Use your own runlevel, runlevel = 2 for Debian family distro

sudo ln -s /etc/init.d/iptables-setup.sh /etc/rc2.d/S90iptables-setup