Vulnerabilities
2008-05-13
Debian openssl package fix predictable random number generator
Debian đã công bố khuyến nghị bảo mật và cung cấp bản vá lỗi cho gói openssl của Debian cho lỗi trong phần sinh số ngẫu nhiên (random number generator). Lỗi được vá trong OpenSSL PRNG (pseudo random number generator) là lỗi do một Debian developer chỉnh sửa lại code của OpenSSL khiến cho bộ sinh số ngẫu nhiên này chỉ được "seed" bởi process pid.
Debian developer vào 05/2006 đã chỉnh sửa lại code của OpenSSL sau khi sửa lỗi "uninitialized variable" do valgrind cảnh báo. Tuy nhiên do không hiểu đây là sự cố tình sử dụng biến không được khởi tạo như một yếu tố "ngẫu nhiễn" của OpenSSL developer, Debian developer đã loại bỏ một số đoạn mã trong hàm PRNG khiến cho cho bộ sinh số ngẫu nhiên này chỉ được "seed" bởi process pid từ hệ thống. Điều này dẫn đến thư viện OpenSSL do Debian cung cấp này chỉ sinh ra 32,768 cặp khóa duy nhất từ PRNG, đồng nghĩa với việc độ an toàn của các khóa RSA, DSA, ... chỉ còn là 15 bits.
Các mã khóa được sinh ra từ các gói có sử dụng thư viện OpenSSL bị lỗi này như SSH, OpenVPN, DNSSEC, X.509 certificates đều cần phải được sinh (generate) lại khóa từ đầu.
Đây là một ví dụ điển hình cho việc vì sao các nhà đóng gói phần mềm không nên tự ý chỉnh sửa code của các thư viện, phần mềm nếu không hiểu rõ về nó và nếu có chỉnh sửa thì nên gửi lại bản patch cho nhà phát triển của gói phần mềm đó để kiểm tra và cập nhật.
Links:
2008-02-22
Software based disk encryption not secure enough!
Researchers at Princeton University has released a white paper named "Lest We Remember: Cold Boot Attacks on Encryption Keys" [1] about gaining access to the contents of a computer's RAM after power off and/or reboot and used it to defeat various popular disk encryption systems such as Microsoft's BitLocker, Apple's FileVault, TrueCrypt, dm-crypt.
Contrary to conventional wisdom, "volatile" semiconductor memory does not entirely lose its contents when power is removed. Both static (SRAM) and dynamic (DRAM) memory retains some information on the data stored in it while power was still applied and they still hold values for a long intervals without power or refresh. This is a known [2] problem for a long long time. However, no one has ever tried (or published) any practical attack on this problem like what Princeton University researchers did.
This DRAM threat goes beyond disk encryption. Any kind of sensitive data such as password, encryption key, credit card information,... in you RAM could be stolen in just a few minutes. Due to the nature of this problem, it's hard for software based hard disk encryption solution to protect against this attack. Software based solution would be able to try to encrypt/clear the disk key whenever PC goes into inactive state (i.e screen saver, standby, hibernate) but it's not really practical and/or applicable in some cases. The white paper [1] also offers interesting algorithms & methods to find crypto keys in memory images.
If you're really care about your information, you should better to change your behavior to unmount encrypted disk and/or power-off your machine (for a while to give the memory enough time to decay) whenever you're away from your computer if you're using software based disk encryption and/or to use a hardware based disk encryption solution. It turns out that the hardware based disk encryption technology that I'm working on would be a perfect solution to help to protect against this kind of attack. For a full protection, our solution still need to fix a small problem when the computer goes into S3 (standby mode) but just a minor change. FYI, Seagate also has a hardware based hard disk encryption solution ready to use.
Links:
- Lest We Remember: Cold Boot Attacks on Encryption Keys
- Secure Deletion of Data from Magnetic and Solid-State Memory
2007-10-29
Buggy HP iPAQ ROM Update Utility
Last weekend I tried to re-flash a HP ipaq rw6828 using the latest HP iPAQ ROM Update 1.01.03 from HP website.

After about 20 minutes, the ROM flash process crashed at 90% and the phone became dead and was not able to power on any longer (tried different suggested methods to get it boot into the bootloader mode but all failed).
I did a quick google on "ipaq 6828 ROM update fail 90%" keywords. Quite a lot of people got the same problem. Some were lucky enough to be able to re-flash the phone again as the phone still can boot into bootloader mode. But many other people had to send the phone to HP Service Center to replace the main board.
So I decided to take a look at the HP iPAQ ROM Update Utility binary (hpRUU.exe - v3.3.2 build 831) to find out the reason.

It didn't take long to find out that the "90%" problem is caused
by a lame buggy code of the HP iPAQ ROM Update Utility itself.

The buggy code is inside the sub_409DA0() (I renamed it to Client_StartFlash()). Below is the reverse C code snippet of ROM update function (not exactly as the asm code)
1:void sub_409520(int c)
2:{
3: DebugLog("odmLib/Client_StartFlash -- Flashing would start here");
4: hEvent = CreateEventA(0, 0, 0, 0);
5: dword_425B04 = CreateThread(0, 0, &sub_409DA0, 0, 0, 0);
6: SetEvent(hEvent);
7:
8: DebugLog("odmLib/Client_StartFlash: pReturnCode->dwError = %d", 65520);
9:}
10:
11:#define FLASH_ERROR(fmt, ...) \
12:{ \
13: DebugLog(fmt, ...); \
14: IsErrorFlag = 1; \
15: pReturnCode_dwError = 401; \
16: return; \
17:}
18:
19:void Client_StartFlash() //sub_00409DA0()
20:{
21: //WORD SelectFile[2];
22:
23: WaitForSingleObject(hEvent, INFINITE);
24: DebugLog("DownloadFile: SelectFile = 0x%x TotalFileSize = 0x%x..\r\n",
25: SelectFile, TotalFileSize);
26:
27: if (DeviceInBLMode == -1) {
28: DebugLog("DownloadFile: DeviceInBLMode has a wrong value!");
29: IsErrorFlag = 1;
30: pReturnCode_dwError = 602;
31: return;
32: }
33:
34: if (SelectFile[0] & 8) {
35: DebugLog("DownloadFile: COM_OS ..\r\n");
36: wsprintfA(StatusBuffer, "Updating the ROM Image ...");
37: byte_425884 = (DeviceInBLMode != 0) + 17;
38: memset(_tFilename, 0, 0x64);
39: pReturnCode_dwExtraInfo = 3;
40: dHeaderLen = 0;
41: sub_40A580(3, _tFilename, (int) &dHeaderLen);
42: DebugLog("DownloadFile: tFilename = %s dHeaderLen = %d\r\n",
43: &_tFilename, dHeaderLen);
44:
45: _hFile = CreateFileA(_tFilename, GENERIC_READ | GENERIC_WRITE, 0, 0,
46: OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
47:
48: if (_hFile == INVALID_HANDLE_VALUE) {
49: FLASH_ERROR("Jcs-CreateFile %s fail .. ", _tFilename);
50: }
51:
52: HeaderBuffer = malloc(dHeaderLen);
53: HeaderBuffer = malloc(dHeaderLen);
54: ReadFile(_hFile, HeaderBuffer, dHeaderLen, &NumberOfBytesRead, 0);
55:
56: dFileLen = GetFileSize(_hFile, 0);
57: dDataLen = dFileLen - dHeaderLen;
58: DataBuffer = calloc(dFileLen - dHeaderLen, 1);
59: ReadFile(_hFile, DataBuffer, dDataLen, &NumberOfBytesRead, 0);
60: free(HeaderBuffer);
61:
62: ROMDecode(dDataLen, DataBuffer);
63:
64: if (memcmp(DataBuffer, 'R000ff\n', 7)) {
65: IsErrorFlag = 1;
66: pReturnCode_dwError = 401;
67: DebugLog("Jcs-Warning: The Image is invalid ... ");
68: wsprintfA(StatusBuffer, "Warning: The Image is invalid ...");
69: return;
70: }
71:
72: if (!bDownLoadThrUSB(DataBuffer, dDataLen, dword_425B20,
73: SelectFile)) {
74: IsErrorFlag = 1;
75: pReturnCode_dwError = 503;
76: return;
77: }
78: free(DataBuffer);
79: CloseHandle(_hFile);
80: }
81:
82: if (SelectFile[0] & 4) {
83: DebugLog("DownloadFile: COM_BL ..\r\n");
84: wsprintfA(StatusBuffer, "Updating the Bootloader ...");
85: dHeaderLen = 0;
86: memset(_tFilename, 0, 0x64);
87: pReturnCode_dwExtraInfo = 2;
88: byte_425884 = 2;
89: sub_40A580(2, _tFilename, (int) &dHeaderLen);
90: DebugLog("DownloadFile: tFilename = %s dHeaderLen = %d\r\n", _tFilename, dHeaderLen);
91: _hFile = CreateFileA(_tFilename, GENERIC_READ | GENERIC_WRITE, 0, 0,
92: OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
93:
94: if (_hFile == INVALID_HANDLE_VALUE) {
95: FLASH_ERROR("Jcs-CreateFile %s fail .. ", _tFilename);
96: }
97: HeaderBuffer = malloc(dHeaderLen);
98: ReadFile(_hFile, HeaderBuffer, dHeaderLen, &NumberOfBytesRead, 0);
99: dFileLen = GetFileSize(_hFile, 0);
100: dDataLen = dFileLen - dHeaderLen;
101: DataBuffer = calloc(dFileLen - dHeaderLen, 1);
102:
103: ReadFile(_hFile, DataBuffer, dDataLen, &NumberOfBytesRead, 0);
104: free(HeaderBuffer);
105: ReadFile(_hFile, DataBuffer, dDataLen, &NumberOfBytesRead, 0);
106: free(HeaderBuffer);
107:
108: ROMDecode(dDataLen, DataBuffer);
109:
110: FILE = fopen("c:\\ipaq\\downloadEboot.txt", "wb");
111: fwrite(DataBuffer, 1, dDataLen, FILE);
112: fclose(FILE);
113:
114: if (!bDownLoadThrUSB(DataBuffer, dDataLen, dword_425B20,
115: SelectFile)) {
116: IsErrorFlag = 1;
117: pReturnCode_dwError = 503;
118: return;
119: }
120: free(DataBuffer);
121: CloseHandle(_hFile);
122: }
123: if (!bDownLoadThrUSB(&unk_4253F0, 0x80, 0, SelectFile)) {
124: IsErrorFlag = 1;
125: pReturnCode_dwError = 401;
126: DebugLog("Jcs-Download version infomation to device fail ..");
127: return;
128: }
129:
130: dTmp = SelectFile[1];
131: if (SelectFile[0] & 0x20) {
132: DebugLog("DownloadFile: COM_FS ..\r\n");
133: dTmp = SelectFile[1];
134: }
135:
136: if (dTmp & 0x80 && dTmp & 0x20) {
137: DebugLog("DownloadFile: COM_WANOS + COM_WANBL ..\r\n");
138: wsprintfA(StatusBuffer, "Updating the Radio Stack ...");
139: dHeaderLen = 0;
140: memset(_tFilename, 0, 0x64);
141: pReturnCode_dwExtraInfo = 15;
142: byte_425884 = 4;
143: sub_40A580(13, _tFilename, (int) &dHeaderLen);
144: DebugLog("DownloadFile: tFilename = %s dHeaderLen = %d\r\n",
145: _tFilename, dHeaderLen);
146:
147: _hFile = CreateFileA(_tFilename, GENERIC_READ | GENERIC_WRITE, 0, 0,
148: OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
149:
150: if (_hFile == INVALID_HANDLE_VALUE) {
151: FLASH_ERROR("Jcs-CreateFile %s fail .. ", _tFilename);
152: }
153:
154: HeaderBuffer = malloc(dHeaderLen);
155: ReadFile(_hFile, HeaderBuffer, dHeaderLen, &NumberOfBytesRead, 0);
156: dFileLen = GetFileSize(_hFile, 0);
157: dDataLen = dFileLen - dHeaderLen;
158: dFileLen = GetFileSize(_hFile, 0);
159: dDataLen = dFileLen - dHeaderLen;
160:
161: DataBuffer = calloc(dDataLen, 1);
162: dword_425B1C = DataBuffer;
163: ReadFile(_hFile, DataBuffer, dDataLen, &NumberOfBytesRead, 0);
164: free(HeaderBuffer);
165: CloseHandle(_hFile);
166:
167: memset(_tFilename, 0, 0x64)
168: sub_40A580(15, _tFilename, (int) &dHeaderLen)
169: DebugLog ("DownloadFile: tFilename = %s dHeaderLen = %d\r\n",
170: &_tFilename, dHeaderLen)
171:
172: _hFile = CreateFileA(_tFilename, GENERIC_READ | GENERIC_WRITE, 0, 0,
173: OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
174:
175: if (_hFile == INVALID_HANDLE_VALUE) {
176: FLASH_ERROR("Jcs-CreateFile %s fail .. ", _tFilename);
177: }
178:
179: HeaderBuffer = malloc(dHeaderLen);
180: ReadFile(_hFile, HeaderBuffer, dHeaderLen, &NumberOfBytesRead, 0);
181: dDataLen = GetFileSize(_hFile, 0) - dHeaderLen;
182: dword_425B84 = dDataLen;
183:
184: DataBuffer = calloc(dDataLen, 1);
185: dword_425B10 = DataBuffer;
186: ReadFile(_hFile, DataBuffer, dDataLen, &NumberOfBytesRead, 0);
187:
188: free(HeaderBuffer);
189: CloseHandle(_hFile);
190:
191: DataBuffer = calloc(dDataLen + nNumberOfBytesToRead + 88, 1);
192: szBuffer = _msize(DataBuffer);
193: memset(DataBuffer, -1, szBuffer);
194:
195: if (sub_40A5E0()) {
196: if (sub_40A770()) {
197: if (sub_40A8F0()) {
198: ROMDecode(Count, DataBuffer);
199: if (DataBuffer) {
200: FILE = fopen ("c:\\ipaq\\downloadMot.txt", "wb");
201: fwrite(DataBuffer, 1, Count, FILE);
202: fclose(FILE);
203: if (bDownLoadThrUSB(DataBuffer, Count, dword_425B20, SelectFile)) {
204: if (sub_40B270()) {
205: free(DataBuffer);
206: free(dword_425B10);
207: free(dword_425B1C);
208: dword_425F58 = 1;
209: } else {
210: IsErrorFlag = 1;
211: } else {
212: IsErrorFlag = 1;
213: pReturnCode_dwError = 401;
214: DebugLog ("Jcs-bGetMOTBurnStatus fail ..");
215: }
216: } else {
217: IsErrorFlag = 1;
218: pReturnCode_dwError = 401;
219: DebugLog ("Jcs-Download Mot fail ..");
220: }
221: } else {
222: IsErrorFlag = 1;
223: pReturnCode_dwError = 401;
224: DebugLog ("Jcs-(pMOTBuf==NULL) fail ..");
225: }
226: } else {
227: IsErrorFlag = 1;
228: pReturnCode_dwError = 401;
229: DebugLog("Jcs-PrepareMOTData fail ..");
230: }
231: } else {
232: IsErrorFlag = 1;
233: pReturnCode_dwError = 401;
234: DebugLog("Jcs-PrepareMOTAgent fail ..");
235: }
236: } else {
237: IsErrorFlag = 1;
238: pReturnCode_dwError = 401;
239: DebugLog("Jcs-PrepareMOTPara fail ..");
240: }
241: } else {
242: dword_425F58 = 1;
243: }
244:}
245:
The codes at line 100->102 and 200->202 inside Client_StartFlash() function try to write the 'decrypted' EBOOT and MOT ROMs data to hard-coded file locations at c:\ipaq\downloadMot.txt and c:\ipaq\downloadEboot.txt. It doesn't check whether the fopen()
return a successful FILE pointer or not before writing the content.
So, If you install the ROM upgrade program in a different location (in my case, i installed it in d:\tmp\ipaq) instead of default location (c:\ipaq), the update program will get crashed at 90%. This stupid error had killed many ipaq and many people had to spend their time and money for the service & mainboard replacement since the update had been released by HP for almost a year. The HP developer who wrote this code should go back to college to learn how to code properly.
After knowing the problem, I sent the ipaq to HP Service Center a day after and got the mainboard replaced. After few hours of waiting, complaining and giving live proof of the bug to HP technical guy, I did not need to pay for mainboard replacement cost :). The technical guy was a nice guy. He even brought me inside HP technical service center for re-flashing few ipaqs to reproduce the problem. However, the experience with the girl at HP Customer Service Center was kind of bad though.
Links: