Archive for 十二月, 2008

同學的Steam帳號被俄羅斯的雜碎盜走了

十二月 29th, 2008

我同學跟我說他收到了email說他Steam的信,要我幫他看看在寫什麼

This email message confirms that your Steam account contact email address has been successfully changed.

We are sending this notice to ensure the privacy and security of your Steam account. If you authorized this change, no further action is necessary. If you did not authorize this change, or if you need additional help with your account, please follow this link to the

http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=197

Thanks for reviewing this information and helping us to maintain the privacy and security of your account.

原來是他的email被改掉了,還不是他改的,看來是被盜帳號了,我還以為只有線上遊戲的帳號有人要盜,沒想道連Steam的帳號都有人要盜= =』,雖然說沒有什麼額外的價值,不過就等於是把整帳號的遊戲全偷走

他改了暱稱以外還把他好友都加進來,原本的好友都被他砍了,看了一下是來自俄羅斯的雜碎

被俄羅斯雜碎盜的Steam帳號

被俄羅斯雜碎盜的Steam帳號

俄羅斯雜碎的好友

俄羅斯雜碎的好友

不過還好留有原本的CD Key應該可以要回來

說到俄羅斯的雜碎,讓我想起GTA IV的Dimitri那個俄國雜碎 XD

話說仔細想一想那個上線的應該不是盜的人,上網找一下似乎是集團有計劃的用bot自動傳送釣魚網頁,所以看來是某個俄國的雜碎想買便宜的L4D或其它裡面的遊戲,不過他買到便宜的遊戲過一陣子就會被拿回去,他的錢也就白花了,科科,這俄羅斯雜碎死好 XD

多Webcam影像合成

十二月 21st, 2008

今天用了兩顆Webcam來做影像的合成,其實還蠻簡單的,最初中間會有條明顯的線,很難看,為此我讓它們之間有一段重疊的地方,然後使用半透明漸層將兩邊影像疊在一起,看起來效果很好,這樣做好處在於可以增加視角,理論上越多顆webcam視角可以越廣,不過缺點在於當物體太靠鏡頭時,看起來就會像斷掉一樣,因為視差的關係,但是無限遠的地方影像應該是重合的,這點應該是沒問題,有圖有真相,以下是我實際測試的畫面

兩個Webcam影像合成畫面

兩個Webcam影像合成畫面

兩顆Webcam

兩顆Webcam

資訊安全的策略 : 深度防禦

十二月 15th, 2008

單薄的防禦

在一般常見的系統中,很常見到只要一個漏洞被發現,然後攻擊,整台電腦就跟著淪陷,為何這麼的容易,原因出在於,防線只有一道,以戰爭來比擬,你的防線可能有十公里,在這十公里中,只要有個洞就可以讓敵人鑽進來,而進來以後就有如入無人之境,以資訊安全來看,假設你的主機是網頁伺服器,你的戰線有OS、SQL Server、Web Server等等各種可能會被攻擊的點,如果你的防線就只有這樣,那麼很可能只要其中一個環節被拿下就等於整台電腦淪陷,不管你再怎麼加強每個層面,世界上沒有不存在漏洞的系統,不存在沒有漏洞的系統,那我們到底能做什麼? 答案就是 : 深度防禦。

什麼是深度防禦(Defence in depth)

深度防禦最經典的應用,應該要算是應用在核能發電廠,我們都知道核能發電廠有著一定的風險,不容許有一絲的差錯,因為核能電廠的安全是極度重要的,因此核能電廠採取就是深度防禦的策略,說了半天,到底什麼是深度防禦,所謂的深度防禦,就是一層防線後面還有一層防線,每層防線都是獨立的,多元化的、且有備援的,舉個例子來說,核能發電需要水來冷卻反應爐,如果第一套水冷系統失效,還有第二套完全獨立的系統在一旁待命,立刻可以接著運作,如果不幸的,連第二套系統也失靈了,我們還有另一道防線,將控制棒插入反應爐吸收中子,就算這層失敗了,後面還有許多許多層的防線,在很外面有一層圍阻體,就算用戰機高速衝撞也不會有事,因此核能電廠是世界上最安全的電廠,因為這一連串防線要全部失效的機率比慧星撞地球還低,每次看到一些沒道德的環保團體欺騙民眾說核電廠會像車諾比那樣炸掉來反核就很火大,回到正題,雖然主題不是核電廠,不過講到這裡我們大概就可以了解,深度防禦的策略,其思維,還有帶來的好處,與壞處,我們接著就來看在資訊安全上要如何應用

  • 多層的防護

一層防禦是不夠的,如你所見只要一層失效了,就等於淪陷,因此深度防禦的理念之一,就是提供多層的保護,一層防火牆不夠? 再加一層,還覺得不夠? 再加一層,不過當然不是加越多防護就越安全,我們繼續看下去

  • 多樣性的防護

試想你加了100層防火牆來保護你重要的資料,但這100層防火牆全用的是同一套防火牆,只要這防火牆被發現某種漏洞,這100層的防火牆很可能變得跟紙一樣,因此多樣性是必要的,例如三層不同的防火牆,以駭客的角度來看,想要進入到最裡層就需要突破三層不同的防火牆,從此看來要強行突入的可能性就大大減少

  • 獨立的組件

系統的運作最好要能盡量獨立,假設所有系統的驗證是靠另一個系統,而只要那個系統被攻破,就等於依賴那個驗證系統的所有系統也跟著一起完蛋,因此獨立性也是非常重要的

  • 備援系統

當你的系統失效時,是否有備援機制? 舉個例子,魔獸世界有通訊鎖,似乎是透過電話來驗證以防止盜帳號,前陣子突然發生通訊鎖失效,玩家抱怨進不了遊戲,於是通訊鎖似乎就因此暫停了小段時間,以攻擊者的角度來看,如果是我要盜取帳號,就可以從這裡下手,首先癱瘓它的通訊鎖,逼他們在玩家的壓力之下把通訊鎖的服務暫時關掉,不必驗證就能登入,如此一來就造成了空檔,之前盜來的帳號本來少了手機驗證這關,無法登入,但是有了這個空檔或許就可以好好利用,從這個例子我們可以看到,重要的系統需要有備援的系統,否則當這個系統失效,就產生了安全性上的問題,而且也可能造成提供攻擊的空檔,駭客可以刻意癱渙該系統以取得攻擊的空檔

  • 最小化的權限

很常見的問題之一,就是使用過大的權限去執行做一些雞毛蒜皮的事,舉個例子,使用root來執行網頁伺服器,在這種情況下,只要網頁伺服器有什麼漏洞因此被利用了,就等於整台電腦的root被拿走了是一樣的,因此使用過大的權限是危險的行為,盡量將權限限制在能做好該做的任務就好的範圍,如此一來,就算某個帳號被拿下,也難以成大事,必須尋求其它管道

  • 不要相信內部系統

即使來到系統內部,也不該相信所有資料不是惡意的,考慮一下如果駭客只拿下最外面的系統,接著要往裡面的系統攻擊,如果裡面的系統天真的以為,來自內部系統的都是安全的,那同樣等於內部的系統也被拿下,因為太相信內部系統而不做檢查的後果,因此就算來到了防線的後方,也不該因此而偷懶不用考慮安全的問題,記得假設你的每個系統都可能被攻擊,就算來自內部的系統也可能是攻擊,你怎麼知道你旁邊的電腦是不是變成殭屍了? 你怎麼知道管理員的介面就不會被殖入XSS因此而不用檢查惡意的html? 因此』不要相信任何人』

現實是…

如果都做到了,攻擊你的系統會是一件非常困難的事,一層防禦還有一層,防禦的種類又是多樣性且不盡相同,都有備援,權限被最小化,即使拿到了也只是個沒什麼用的使用者,而系統內部也不相信其它系統,拿下來外圍的系統想藉此攻擊內部也是很困難,是的,理論上來講非常困難,但是真正值得考慮的應該是到底能夠做到多少? 越多越繁複的防禦表示越高的成本,想像一下你會拿這樣的方式來防禦王小明寫給隔壁阿花的情書嗎? 我想不會,除非那個很重要,但是相對的,如果是核子彈發射的系統,這樣做就很值得,你不會想看到核子武器把玩在script kid的手中吧? 因此深度防禦如果真的要達到有深度確實要花不少成本,但是其實不用很深,我們保護的不是核子彈,就算是客戶的資料,我們一樣可以盡量增加防禦的深度,事實上不用太深的深度,當你的資料沒有那個價值讓駭客去花那麼大的力氣取得時,到那樣的深度其實就已經足夠

簡單版本的視覺化tracert

十二月 14th, 2008

我整合了一下之前的程式,做出一個簡單版本的視覺化tracert,目前因為mapnik的地圖有些功能還不能實作,不能動態去修改地圖資料,目前只能修改地圖呈現的方式,因此我以目前只能以顏色來表示router的順序,綠色是較先連到的router,紅色是較後面連到的router

視覺化顯示router所在國家

視覺化顯示router所在國家

還有不少問題要解決,原本使用的資料ip to country只能精確到國家,因此在同一個國家裡繞好幾次就看不出來,因此之後會改成使用ip to city的資料,不過檔案還真不小,就算是binary的形式也有25MB,這還算好辦,大不了開網頁解析就能線上查城市位址而不用下載所有資料,世界城市的地圖資料要從哪裡來還是另一個比較麻煩的問題

而這張圖是tracert www.google.com的結果,如大家所見的,最近不知道為什麼暴慢,hinet不知什麼原因,把google繞到日本去,這就令人匪疑所思,有人知道其中的八掛嗎? Google和hinet到底是出什麼問題呢,會讓hinet把google繞到日本去

Python實作tracert

十二月 14th, 2008

為了要能寫出可以在地圖上看到router所在地的程式,我用Python加上RAW_SOCKET實作了tracert的功能,封包格式的部份我直接使用這個recipe,不過好像有用到一些過時的東西會跑出警告還需要處理

import struct
import socket
 
class Packet(object):
 
    """Creates ICMPv4 and v6 packets.
 
    header
        two-item sequence containing the type and code of the packet,
        respectively.
    version
        Automatically set to version of protocol being used or None if ambiguous.
    data
        Contains data of the packet.  Can only assign a subclass of basestring
        or None.
 
    packet
        binary representation of packet.
 
    """
 
    header_table = {
                0 : (0, 4),
                #3 : (15, 4),  Overlap with ICMPv6
                3 : (15, None),
                #4 : (0, 4),  Deprecated by RFC 1812
                5 : (3, 4),
                8 : (0, 4),
                9 : (0, 4),
                10: (0, 4),
                11: (1, 4),
                12: (1, 4),
                13: (0, 4),
                14: (0, 4),
                15: (0, 4),
                16: (0, 4),
                17: (0, 4),
                18: (0, 4),
 
                1 : (4, 6),
                2 : (0, 6),
                #3 : (2, 6),  Overlap with ICMPv4
                #4 : (2, 6),  Type of 4 in ICMPv4 is deprecated
                4 : (2, None),
                128: (0, 6),
                129: (0, 6),
                130: (0, 6),
                131: (0, 6),
                132: (0, 6),
                133: (0, 6),
                134: (0, 6),
                135: (0, 6),
                136: (0, 6),
                137: (0, 6),
             }
 
    def _setheader(self, header):
        """Set type, code, and version for the packet."""
        if len(header) != 2:
            raise ValueError("header data must be in a two-item sequence")
        type_, code = header
        try:
            max_range, version = self.header_table[type_]
        except KeyError:
            raise ValueError("%s is not a valid type argument" % type_)
        else:
            if code > max_range:
                raise ValueError("%s is not a valid code value for type %s" %\
                                     (type_, code))
            self._type, self._code, self._version = type_, code, version
 
    header = property(lambda self: (self._type, self._code), _setheader,
                       doc="type and code of packet")
 
    version = property(lambda self: self._version,
                        doc="Protocol version packet is using or None if "
                            "ambiguous")
 
    def _setdata(self, data):
        """Setter for self.data; will only accept a basestring or None type."""
        if not isinstance(data, basestring) and not isinstance(data, type(None)):
            raise TypeError("value must be a subclass of basestring or None, "
                            "not %s" % type(data))
        self._data = data
 
    data = property(lambda self: self._data, _setdata,
                    doc="data contained within the packet")
 
    def __init__(self, header=(None, None), data=None):
        """Set instance attributes if given."""
        #XXX: Consider using __slots__
        # self._version initialized by setting self.header
        self.header = header
        self.data = data
 
    def __repr__(self):
        return "" % \
                (self.version, self.type, self.code, len(self.data))
 
    def create(self):
        """Return a packet."""
        # Kept as a separate method instead of rolling into 'packet' property so
        # as to allow passing method around without having to define a lambda
        # method.
        args = [self.header[0], self.header[1], 0]
        pack_format = "!BBH"
        if self.data:
            pack_format += "%ss" % len(self.data)
            args.append(self.data)
        # ICMPv6 has the IP stack calculate the checksum
        # For ambiguous cases, just go ahead and calculate it just in case
        if self.version == 4 or not self.version:
            args[2] = self._checksum(struct.pack(pack_format, *args))
        return struct.pack(pack_format, *args)
 
    packet = property(create,
                       doc="Complete ICMP packet")
 
    def _checksum(self, checksum_packet):
        """Calculate checksum"""
        byte_count = len(checksum_packet)
        #XXX: Think there is an error here about odd number of bytes
        if byte_count % 2:
            odd_byte = ord(checksum_packet[-1])
            checksum_packet = checksum_packet[:-1]
        else:
            odd_byte = 0
        two_byte_chunks = struct.unpack("!%sH" % (len(checksum_packet)/2),
                                        checksum_packet)
        total = 0
        for two_bytes in two_byte_chunks:
            total += two_bytes
        else:
            total += odd_byte
        total = (total >> 16) + (total & 0xFFFF)
        total += total >> 16
        return ~total
 
    def parse(cls, packet):
        """Parse ICMP packet and return an instance of Packet"""
        string_len = len(packet) - 4 # Ignore IP header
        pack_format = "!BBH"
        if string_len:
            pack_format += "%ss" % string_len
        unpacked_packet = struct.unpack(pack_format, packet)
        type, code, checksum = unpacked_packet[:3]
        try:
            data = unpacked_packet[3]
        except IndexError:
            data = None
        return cls((type, code), data)
 
    parse = classmethod(parse)
 
def tracert(host, callback, maxTTL=128, icmpData="Yo, what's up?"):
    import os
    host = socket.gethostbyname(host)
    # create socket
    s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname('icmp'))
    pid = os.getpid()
    icmp = Packet((8,0))
    icmp.data = icmpData
    for i in range(1, maxTTL):
        # set ttl
        s.setsockopt(socket.IPPROTO_IP, socket.IP_TTL, i)
        # send icmp packet
        s.sendto(icmp.packet, (host, 0))
        # receive result
        data, address = s.recvfrom(1024)
        # parse result icmp packet
        result = Packet.parse(data[20:])
        # callback
        callback(address[0], result)
        type, code = result.header
        if type == 0:
            break
 
__all__ = [
    'tracert',
    'Packet'
]
 
if __name__ == '__main__':
    def printIp(address, packet):
        print address
    tracert(raw_input('Host to trace router:'), printIp)

Mapnik整合wxPython

十二月 14th, 2008

什麼是Mapnik

Mapnik是一款Open source的地圖繪製的程式庫,它可以畫出非常漂亮的地圖,也可以做出像Google Map那樣的地圖,例如這個範例,不過它還算是在開發中,文件還有點不太齊全,因為我想做一套自己的VisualTracert來顯示tracert的router分部在世界的哪裡,那套VisualTracert是商業軟體,要看地圖是要錢的,因此我想弄一個Open source的版本,不過因為還很新,有的應用目前幾乎都是網頁地圖,GUI的例子很少,我花了一點時間,研究如何將地圖畫到wxPython上

程式其實不難,只是mapnik文件都還沒建好,要用dir函數和看原始碼去了解到底有什麼功能可以用,以下就是使用wxPython來畫mapnik地圖的程式

"""
This is a simple wxPython application demonstrates how to
integrate mapnik, it do nothing but draw the map from the World Poplulation XML
example:
http://trac.mapnik.org/wiki/XMLGettingStarted
 
Victor Lin. (bornstub@gmail.com)
Blog http://blog.ez2learn.com
 
"""
 
import wx
import mapnik
 
class Frame(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, size=(800, 500) ,*args, **kwargs)
        self.Bind(wx.EVT_PAINT, self.onPaint)
 
        self.mapfile = "population.xml"
        self.width = 800
        self.height = 500
        self.createMap()
        self.drawBmp()
 
    def createMap(self):
        """Create mapnik object
 
        """
        self.map = mapnik.Map(self.width, self.height)
        mapnik.load_map(self.map, self.mapfile)
        bbox = mapnik.Envelope(mapnik.Coord(-180.0, -75.0), mapnik.Coord(180.0, 90.0))
        self.map.zoom_to_box(bbox)
 
    def drawBmp(self):
        """Draw map to Bitmap object
 
        """
        # create a Image32 object
        image = mapnik.Image(self.width, self.height)
        # render map to Image32 object
        mapnik.render(self.map, image)
        # load raw data from Image32 to bitmap
        self.bmp = wx.BitmapFromBufferRGBA(self.width, self.height, image.tostring())
 
    def onPaint(self, event):
        dc = wx.PaintDC(self)
        memoryDC = wx.MemoryDC(self.bmp)
        # draw map to dc
        dc.Blit(0, 0, self.width, self.height, memoryDC, 0, 0)
 
if __name__ == '__main__':
    app = wx.App()
    frame = Frame(None, title="wxPython Mapnik Demo By Victor Lin")
    frame.Show()
    app.MainLoop()
wxPython整合Mapnik示範程式畫面

wxPython整合Mapnik示範程式畫面

別讓危險成為預設的行為,讓危險的行為比安全的行為更麻煩

十二月 13th, 2008

危險的行為

對於寫程式而言,很多預設的行為都是相當危險的,舉一些最常見的例子SQL Injection、XSS、Buffer overflow,我們可以從這些幾個最常出現被攻擊的類形,都有一個共同的特點,就是它們通常都是因為預設的行為很危險,我們一個一個來看

» Read more: 別讓危險成為預設的行為,讓危險的行為比安全的行為更麻煩

如何放置funp推文按鈕在Wordpress的文章右上方

十二月 9th, 2008

似乎很多網站都這麼做,把funp推文按鈕放在文章左上角,推文章好像還蠻方便的,我就研究了一下,方法如下

首先來到funp的推文按鈕產生器,接著以

<? php the_permalink() ?>

來產生推文按鈕,選擇』多個推文按鈕』

funp推文按鈕步驟1

funp推文按鈕步驟1

接著把下面放在<head>的程式碼:

<script language=』JavaScript』 src=』http://funp.com/tools/js/funp_button.js』></script>

複製後貼到佈景主題編輯器的header.php的如下圖所示的位置上,完成修改後記得按更新檔案

funp推文按鈕步驟2

funp推文按鈕步驟2

接著把上面欄位裡的程式碼:

<script>funp_genButton(‘<? php the_permalink() ?>’, 1);</script>

貼到如下圖所示在index.php的位置

為了讓它能夠靠右邊,我做了一點修改,在外面加上往右浮動的div,因此你也可以這樣寫,就可以得到靠右對齊的效果

<div style=』float: right;』><script>funp_genButton(‘<?php the_permalink() ?>’, 1);</script></div>

修改完成後一樣按更新檔案

funp推文按鈕步驟3

funp推文按鈕步驟3

接著我們再把上面同樣的程式碼貼到single.php如下圖所示的位置上

funp推文按鈕步驟4

funp推文按鈕步驟4

修改完成後一樣按更新檔案,就大工告成了

如果你跟我用一樣的佈景應該不會有什麼問題,如果不是的話,那就得自行找出正確的插入位置囉

這年頭連垃圾廣告信都能爭眼說瞎話

十二月 9th, 2008

我還以為只有詐騙集團才能睜眼說瞎話,沒想到這年頭連網站行銷都能這樣幹,話說我已經對垃圾信沒有什麼感覺,但是還是一樣的原則,透過垃圾信行銷的網站、產品,絕對是不屑一顧

對於垃圾信是如此,對於佯裝成系統信件、朋友信件等等的垃圾信更是如此,剛才就收到這麼一封

不要臉的廣告信

不要臉的廣告信

如果您確實未曾在瘋狂賣客crazymike購買過任何東西,沒關係,但這也很有可能是我們電腦自動挑選的通知名單有誤,這表示您是多麼的幸運才會接到我們的通知。

哇~ 好幸運喔,這擺明是把所有人當白痴是嗎? 幸運個屁,連聽都沒聽過這什麼鬼網站,為什麼會有我信箱,更不可能購什麼物,加了這段文字根本更是此地無銀三百兩,還電腦自動挑選的通知名單有誤,去你的通知名單有誤,憑空生出我的信箱,不! 應該說是去買到信箱資料庫,這程式還真神奇阿,我只能說

電腦選的麻!? 我知道阿,土豆也是電腦選的

再者,就算真的沒買過東西居然會收到訂單通知信,那更讓人覺得這網站還真可靠,事關商譽的訂單信居然能這樣亂寄,哪裡來的天兵能想到這種腦殘行銷方法,請大家唾棄不要臉的不誠實的行銷方式