|
|
@StarGhost: mình không đồng ý với việc applied crypto của bruce schneier là đáng vứt đi. mình nghĩ dùng nó để tra cứu thì vẫn được, nhất là khi tra cứu các protocol.
Về nhận định khi nào cần (kiến thức toán/tin) thì thêm vào thì đây chính là điều mình đang muốn nói. Hầu như các tác giả chỉ trình bày rất qua loa, mặc dù theo mình thấy thì những kiến thức đó là rất cần. Ví dụ trong các cuốn sách về crypto, hầu như chỉ duy nhất cuốn của Stinson là dành ra một chương để bàn về information theory của Shannon. Các cuốn còn lại đều rất ít đề cập, hoặc là chỉ đưa kết quả, mà không giải thích.
Các lĩnh vực toán tin mà mình đưa ra cũng hết sức rộng lớn, mà crypto chỉ ứng dụng một phần nhỏ trong đó. Nếu các tác giả tập trung viết về các phần này thì mình nghĩ cũng chẳng làm cho sách quá dày và khó viết. Thật tế là mình thấy lecture notes của các khóa crypto của nhiều trường viết rất tốt về các mảng đề tài này, nhưng chẳng hiểu sao lúc viết thành sách crypto thì chẳng ai buồn thêm chúng vào.
Có lẽ chỉ có mỗi Stinson là viết tương đối đầy đủ nhất, nên sách của ổng được dùng làm textbook. Nếu mai mốt mình có viết một cuốn sách crypto tiếng Việt, thì mình hứa sẽ viết đầy đủ hết các cơ sở toán học của nó ha ha ha.
|
|
|
@StarGhost: mình thấy nếu nói về classic crypto thì hay nhất là cuốn Cryptanalysis của Helen Gaines.
Về cuốn của Stinson thì mình thấy nhiều khóa dạy crypto ở các trường đại học đều lấy cuốn đó làm textbook hay reference. Thầy mình cũng giới thiệu cuốn đó cùng với cuốn HAC để đọc thêm.
Bàn thêm một chút về sách crypto, mình thấy một vấn đề lớn là các sách thường không bàn chi tiết và đầy đủ về các lĩnh vực toán học mà crypto được xây dựng trên đó. Thường tác giả chỉ nói chung chung, hoặc liệt kê mà không chứng minh. Thậm chí những cuốn rất nổi tiếng như Applied Cryptography thì hầu như không đề cập gì đến toán học luôn (có 1 chương nói về toán, nhưng chỉ là để giới thiệu, không có liên quan mấy đến toàn bộ nội dung của cuốn sách).
Mà để học về crypto, thì người học phải hiểu rõ linear algebra, probability theory, number theory, abstract algebra. Đó là chưa kể một món rất khó nuốt là computation and complexity theory.
Không biết bạn StarGhost có giới thiệu cuốn nào về crypto mà có bàn chi tiết đến những món toán/tin kể trên không?
|
|
|
@Fal: mình toàn học trên trời không àh, không có bài nào đơn giản hết trơn.
hehehe nói đùa thôi, mình đang phải chiến đấu với mấy khái niệm toán học được sử dụng trong crypto hiện đại, nên chưa có thời gian để mà soạn lại các bài crypto cổ điển này.
nhưng chắc chắn trong thời gian tới mình sẽ gửi mấy cái homework của mình lên đây để nhờ các bạn giúp mình giải chúng.
|
|
|
Cái này là Vigenere cipher. Muốn phá nó thì phải làm hai việc:
1. Tìm key length. Có thể làm bằng phương pháp Kasaki. Đại loại ý tưởng là tìm những đoạn lập lại trong ciphertext, rồi dựa vào đó mà tính ra key length.
2. Có key length rồi thì mọi thứ sẽ trở nên đơn giản. Viết ciphertext lại theo từng nhóm có độ dài bằng key length, xếp chồng lên nhau, sẽ tạo thành key-length cột. Xét riêng từng cột thì mỗi cột sẽ là một cái Caesar cipher, nên có thể dùng phương pháp tính frequency để tìm ra plaintext và key.
|
|
|
@VaT: lỗi đó nghiêm trọng àh nha. Trong trường hợp khác thì rất dễ crash hoặc thậm chí là chạy mã luôn (coi topic tìm lỗi chương trình C của mình). Mình đang suy nghĩ xem trong trường hợp này thì làm sao crash được chương trình của bạn.
|
|
|
VaT wrote:
Một vòng lặp. Bạn đọc kĩ để hiểu giải thuật nhé.
Code:
#include "stdafx.h"
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int _tmain(int argc, _TCHAR* argv[])
{
int NumId[10]={0,0,0,0,0,0,0,0,0,0};
double CurNum=0;
int MaxNum,TempNum;
MaxNum = 0; TempNum = 0;
cout << "Nhap vao mot so: ";
cin >> CurNum;
while (CurNum!=0)
{
TempNum = (int)CurNum % 10;
if (MaxNum <= TempNum) MaxNum = TempNum;
NumId[TempNum]++;
CurNum = (CurNum-TempNum)/10;
}
cout << "So Max : "<< MaxNum << endl <<"So luong:"<<NumId[MaxNum]<< endl;
return 0;
}
Nếu mình nhập vào một số âm cho CurNum thì chuyện gì sẽ xảy ra nhỉ? :-p
|
|
|
@StarGhost: đồng ý.
@rongchaua: mình không biết.
Mình cũng đồng ý với StarGhost là một khi đã phát hiện đó là stream cipher, thì việc đầu tiên cần làm là thử XOR plaintext với ciphertext để tìm keystream. Nếu XOR xong, ra keystream, không biết được nó là gì thì mới thử tiếp các thể loại transposition/substitution cipher truyền thống (nhưng đối với software hiện đại thì xác suất chúng nó sử dụng mấy loại này là cực thấp).
Mình chưa thấy stream cipher nào dùng OR cả. Đơn giản là vì sao mà dùng OR được :-p.
|
|
|
nếu mình nhớ không lầm thì nó chỉ đơn giản xor mấy cái msg với cái id của user.
|
|
|
Mình mới tìm được một số tài liệu khá hay trên mạng về đề tài này, các bạn tham khảo nha:
1. Chương 6 - C language issues của The Art of Software Security Assessment (được xem là sách gối đầu giường của những ai muốn nghiên cứu việc tìm lỗi trong phần mềm, một trong rất ít cuốn sách làm thay đổi cả ngành an toàn thông tin): http://www.awprofessional.com/content/images/0321444426/samplechapter/Dowd_ch06.pdf.
Chương 6 này viết rất chi tiết về các vấn đề thường gặp khi lập trình bằng ngôn ngữ C.
2. Chương 5 của cuốn "Secure Coding in C and C++", tác giả là Robert Seacord, chuyên gia về viết mã an toàn của CERT: http://www.awprofessional.com/content/images/0321335724/samplechapter/seacord_ch05.pdf
Chương 5 này viết rất chi tiết về các vấn đề liên quan đến số nguyên. Khác với cuốn ở trên, Seacord còn đưa ra một số biện pháp để viết mã an toàn hơn.
3. Tham khảo thêm tài liệu https://www.securecoding.cert.org/confluence/display/seccode/CERT+C+Programming+Language+Secure+Coding+Standard. Trong đây họ liệt kê tất cả các dạng lỗi thường gặp khi viết bằng C, và cách sửa chương trình để không bị lỗi nữa.
|
|
|
http://www.mediafire.com/download.php?zymq4nzn2yl
|
|
|
Hôm nay có bạn gửi cho 3 cái binary, một phần của CodeGate2009, nói là có liên quan đến đề tài đang thảo luận ở đây. Mình xem thử qua, thấy đúng thế thiệt. Mời các bạn nhào vào exploit nha:
1. hotdog: http://www.mediafire.com/?jtcd5iyhomv
2. sandwich: http://www.mediafire.com/?znuf2wt4tuo
3. hamburger: http://www.mediafire.com/?znuf2wt4tuo
|
|
|
@Z0rr0: ủa chứ HVA không phải là viết tắt của Hacker Vietnam Association hả bạn? mình thấy logo cũng nhấn mạnh đến security, programming, design và hacking mà?
nếu không phải thì xin lỗi. chắc mình nhầm forum rồi. cứ tưởng nơi đây phải thảo luận chuyên sâu về 4 đề tài ở trên chứ, ai dè đâu...
PS: vụ ở topic "tìm thuật toán" là mình nhầm lẫn, không phải cố ý. Có lẽ suy thoái kinh tế làm bạn Z0rr0 bị stress chăng? Nhầm lẫn mà cũng bị cảnh cáo? Nếu các bạn admin thật sự khó tính như thế thì mấy topic như thế này, không nằm trong mục tiêu của diễn đàn, phải bị dẹp đi rồi chứ nhỉ?
Mình thấy cái gì cũng bàn, riết sẽ trở thành cái chợ.
|
|
|
Hình như có bạn nào đó delete bài của mình phải hông? Hay là mình bị dejavu ta? Nhớ reply trong topic này rồi mà :-D.
@devilmaycry281: giờ mình chỉ cho bạn một ý hay hơn nè. Code của thầy bạn quá trời lỗ hổng an ninh, thử tìm đi, rồi báo lại cho ổng. Biết đâu sẽ được điểm cộng sao.
|
|
|
hahaha các hacker nhà ta giờ toàn bàn chuyện làm sao để tìm trên Google. quá siêu.
|
|
|
Cái này lạ àh. Mình chưa thấy cipher nào nhận vào input 128 bit rồi xuất ra ouput 200 bit hết trơn. Bạn có thể thực hiện được loại attack nào? Nếu làm được chosen-plaintext thì thử nhập vào nhiều plaintext coi, thử nhập 16 byte 0 coi ra gì? Có thêm thông tin gì nữa hông?
|
|
|
trời mua server chi bạn? ồn ào, tốn điện, đồ cũ thì dễ bị hư nữa. mấy cái này chỉ cần bạn đi làm 1 tháng là học được hết, không cần phải *luyện* trước đâu.
|
|
|
Lập trình, lập trình và lập trình. Ráng viết C/C++ trên Windows/Linux cho đến khi viết được device driver là ngon.
|
|
|
@nbthanh: rất vui là cuối cùng bạn cũng đã đọc cái spec. Mình thấy cái 6.4.8 nó đã ghi rõ rồi mà, mấy cái preprocessing number sẽ chỉ có hai kiểu: hoặc là float hoặc là integer, nó đâu có ghi là sẽ phụ thuộc vào ngữ cảnh đâu bạn :-p. Việc convert một token sang loại token nào chỉ phụ thuộc vào cái literal string của token đó thôi, không hề phụ thuộc vào ngữ cảnh. Đây là kiến thức cơ bản của môn compiler mà phải không? Rồi từ loại token, người ta mới suy ra kiểu của token đó. Cái này mình đã nói ở trên rồi, kiểu của MAX_LEN sẽ là int.
Nếu MAX_LEN là int, thì biểu thức MAX_LEN - 1 sẽ có kết quả thuộc kiểu int (như mình đã chứng minh bằng sizeof). Đây cũng là điểm mà mình muốn nói đến từ đầu. Thậm chí sizeof(MAX_LEN - 1) cũng bị dịch một phát thành movel 0x4, $eax, nghĩa là compiler nó tính ra giá trị cụ thể (mình nghĩ là nó làm ở bước translation 7), rồi ghi luôn vào register, chứ không hề sinh mã trung gian.
Nếu không lầm thì mình đã đưa ra một ví dụ có mã trung gian cho bạn rồi. Chắc là bạn bỏ sót, giờ mình đưa ra một ví dụ mà mình vừa mới nghĩ ra:
Code:
int main(int argc, char **argv)
{
int i;
i = MAX_LEN-10;
char c = (char)(MAX_LEN - 10);
printf("%d %d %d\n", i, c);
return 0;
}
Nhìn vào cái char c = (char)(MAX_LEN - 10); thì nếu mà tính như bạn nghĩ, char c = (char) ((char)MAX_LEN - (char)10)); nói cách khác compiler xem MAX_LEN là char, 10 là char, tính ra kết quả, rồi gán luôn cho char, thì việc convert (char) một lần nữa ở biểu thức (MAX_LEN - 10) sẽ không có ý nghĩa. Nên compiler sẽ phải output dạng như bạn nbthanh suy đoán, mov -10, register.
Dẫu vậy lúc disassembly thì mình thấy gì?
Code:
0x08048385 <main+17>: movl $0xf6,-0xc(%ebp)
0x0804838c <main+24>: movb $0xf6,-0x5(%ebp)
Thấy cái movb không bạn? Nó đưa vào 0xf6 = 246 (nó sẽ không ra được giá trị này nếu như nó áp dụng cách tính của bạn) luôn, nhưng chỉ move một byte cuối thôi. Không hề xuất hiện cái -10 như bạn nghĩ :-D.
Nếu mình đổi short c = (short)(MAX_LEN - 1), thì compiler sẽ output:
Code:
short c = (short)(MAX_LEN - 1)
...
0x0804838c <main+24>: movw $0xf6,-0x6(%ebp)
Rõ ràng hai ví dụ này chứng minh rất rõ là MAX_LEN - 1 sẽ có kiểu là integer (nó mới tính ra được cái giá trị 0xf6). Đấy, mình nghĩ từ đầu đến giờ, hai ví dụ này là convincing nhất. Bạn nbthanh mà không đồng ý nữa thì mình ráng tìm cái khác nữa vậy.
Dẫu vậy, mình cũng cảm ơn bạn nbthanh là nhờ có bạn thắc mắc kỳ cục mà mình có dịp hiểu hơn về vấn đề này.
|
|
|
Mình nghĩ bạn StarGhost nói đúng rồi đó. Coi thêm cái này http://en.wikipedia.org/wiki/Exec_Shield
|
|
|
@nbthanh: không phải chẳng may mà hai cái bạn tính nó ra kết quả giống nhau đâu, tự vì nó bắt buộc phải giống nhau, bạn thử lấy giấy viết ra tính thử xem sẽ thấy.
Mình có làm một chương trình nhỏ thế này, mong là bạn nbthanh sẽ đồng ý với những luận điểm ở trên của mình sau khi xem chương trình này:
Code:
#include <stdlib.h>
#include <stdio.h>
#define MAX_LEN 256
int main(int argc, char **argv)
{
short i;
i = MAX_LEN-10;
printf("%d %d\n", i, sizeof(MAX_LEN-10));
return 0;
}
Lưu ý là mình đổi i từ int sang short, để bạn nbthanh thấy là compiler cũng bỏ bước trung gian ở trường hơp này luôn. Lưu ý thứ hai là sizeof(MAX_LEN-10) là 4.
|
|
|
nbthanh wrote:
nbthanh wrote:
Tuy nhiên ở đây compiler lại không sinh ra lệnh nào cho phép tính 256-10 mà asm code ra thằng luôn: movb $-10, -5(%ebp). Như vậy thì luận chứng của bạn choc_ chưa thể kiểm chứng được (tôi không nói là sai nhé).
Nói rõ thêm điểm này 1 chút: làm sao để kiểm chứng được là với câu lệnh:
c = MAX_LEN - 10; (c = 256-10) thì compiler sẽ thực hiện:
c = (char)((int)256 - (int)10)
hay là c = (char)256 - (char)10
Thì tại chuẩn (với lại tại hai khứa K&R) yêu cầu phải thực hiện cái đầu tiên chứ sao, khổ thât. Mà thật ra nếu bạn có ghi biểu thức [b]c = (char)256 - (char)10[b/] thì compiler cũng sẽ thực hiện tuần tự các bước sau đây (thấy có vẻ quái dị):
1. Gán kiểu int cho 256 và 10 (do luật xử lý integer constant)
2. Ép kiểu 256 và 10 xuống thành char (do luật simple conversion)
3. Nâng lên int hai số vừa ép xuống char (do luật integer promotion)
4. Tính ra giá trị (kiểu int) của vế phải
5. Ép giá trị này từ int xuống char, và gán lại cho c.
Chứ nó sẽ không như bạn nghĩ (mình đoán bạn đang nghĩ vậy) là ép kiểu xuống char, trừ phát, rồi assign luôn. Mà bạn cũng lưu ý ghi (char) 256 nghĩa là ép kiểu, mà muốn ép kiểu thì 256 phải có kiểu rồi, và kiểu đó là int.
Dẫu vậy mình nghĩ suy nghĩ của bạn là có lý, nhưng tại sao C lại không làm như bạn nghĩ, thì đơn giản vì hai khứa K&R không thích thế. Nếu bạn nghĩ cách của bạn hay hơn, thì bạn tự viết compiler rồi ra chuẩn riêng cho mình nha.
Vậy thôi, dừng tranh luận vấn đề này nha, mình chán rồi. Bạn không chịu đọc những gì mình viết và tài liệu mình gửi lên đây.
|
|
|
@nbthanh: mình không rõ bạn không hiểu thật hay vì lý do gì đó mà cố tình không hiểu. Việc tại sao compiler ra được giá trị -10, và ghi thẳng vào vùng nhớ của biến c thì mình đã giải thích ở trên rồi. Mình giải thích cách compiler sẽ phải làm từng bước, khi muốn xác định kiểu của biểu thức MAX_LEN - 10, nhưng không có nghĩa là compiler bắt buộc phải sinh mã cho từng bước đó.
Nếu mình tính được c, thì người viết compiler cũng sẽ tính được c, vậy thì tội dại gì phải sinh mã trung gian (nhất là khi vế phải chỉ là một integer constant expression)? Đây chỉ là một bước tối ưu mã rất bình thường mà bất kỳ ai viết compiler cũng phải nghĩ đến.
Mình chưa làm thử, nhưng mình đồ là thay vì gán trực tiếp MAX_LEN - 1 cho c, bạn thử ép kiểu từ i qua c, thì bạn sẽ thấy đoạn mã mà bạn đang tìm, bởi lúc này vế phải không còn là một integer constant expression nữa rồi.
Mà thôi, mình làm luôn cho bạn coi nè (compiled bằng gcc-4.x trên linux-x86):
Code:
i = MAX_LEN-10;
c = (char) i;
.....
0x08048385 <main+17>: movl $0xf6,-0xc(%ebp)
0x0804838c <main+24>: mov -0xc(%ebp),%eax
0x0804838f <main+27>: mov %al,-0x5(%ebp)
Ở cái lệnh assembly đầu tiên, do tính được giá trị của MAX_LEN - 10, nên compiler nó ghi luôn vào ô nhớ của i. Ở 2 lệnh tiếp theo, compiler nó thực hiện cái mà bạn nbthanh đang tìm kiếm.
Mình cũng không tự dưng dựa vào một hai quan sát (mà mình cũng đã dùng luật để giải thích ngọn ngành) mà phán như bạn, mình nói có sách, mách có chứng đàng hoàng, bạn cố tình không chịu đọc chứng cứ mình đưa ra đó thôi.
|
|
|
Mình nghĩ những tranh luận ở đây thể hiện rất rõ lý do tại sao mình gửi mấy bài này lên đây: ngay cả người đã làm C/C++ nhiều năm vẫn có thể không hiểu rõ cách mà C/C++ xử lý các con số. Mà không chỉ trong C/C++, vấn đề này cũng lập lại ở các ngôn ngữ như Java hay C#. Nên mình có lời khuyên là bạn nào viết code để sống thì nên tìm hiểu kỹ những câu hỏi này, xem mình có thật sự hiểu rõ chuyện gì xảy ra hay không.
|
|
|
@nbthanh: mình nghĩ bạn nên đọc C99 đi, tự vì trong đó nó nói hết tại sao bạn lại quan sát được như thế. Và rất tiếc là C99 nó nói khác với cách hiểu của bạn.
Thật tế với ví dụ của bạn, không cần phải compile rồi chạy, mình cũng có thể tính được giá trị của hai biến i và c, thông qua các luật chuyển đổi trong C99.
Như mình đã nói ở một bài ở trên, MAX_LEN, sau bước preprocessing, trở thành 256, và sẽ được xem như là một integer constant. Để tính kiểu cho một integer constant, thì C99 (các chuẩn trước đó thì hình như chưa có luật n), sẽ tìm chọn từ trên xuống dưới, bắt đầu bằng int (rồi long int, rồi long long int...), xem kiểu nào có thể lưu giá trị của integer constant đó. Ở trường hợp này, do MAX_LEN là 256, nên kiểu được chọn là int. Sở dĩ C99 không chọn kiểu nhỏ hơn, ví dụ như char hay short, bởi vì các kiểu này, sau đó cũng sẽ bị đổi sang int, do phép biến đổi integer promotion.
Biểu thức 256 - 10 là một biểu thức số học nhị phân, nên việc tính kiểu cho nó sẽ tuân theo nhóm luật gọi là usual arithmetic conversion. Ở đây mình có hai cái operand cùng kiểu int, nên không cần phải chuyển đổi gì thêm nữa, biểu thức này sẽ có kiểu là int. Trong C99 cũng có nói, int là signed hay unsigned là implementation-defined, và thông thường thì nó sẽ là signed.
Rồi bây giờ nói đến hai trường hợp cụ thể mà bạn nbthanh quan sát được. Trong trường hợp i = MAX_LEN - 10, do i được khai báo là int, cùng kiểu với MAX_LEN - 10, nên giá trị của MAX_LEN - 10 sẽ được gán cho i mà không cần phải chuyển đổi gì nữa. Trong trường hợp c = MAX_LEN - 10, do c là char, nên khi gán thế này, một phép biến đổi từ int sang char (mà C99 gọi là simple conversion) sẽ diễn ra: số int sẽ bị truncated, chỉ lấy 8 bit cuối của số int này, và gán cho số char.
Xét 8 bit cuối của số 246 = MAX_LEN - 10: 1111 0110. 8 bit này là dạng biểu diễn lưu trên máy tính của c. Tương tự, như trường hợp int, char là signed hay unsigned là implementation-defined, và thông thường là signed. Nghĩa là muốn tính xem 1111 0110 là biểu diễn của con số bao nhiêu, ta phải lấy bù hai của nó.
Bù một: 0000 1001
Bù hai: 0000 1010 = 10
Như vậy 1111 0110 là biểu diễn của giá trị là -10. Điều này giải thích tại sao bạn nbthanh thấy giá trị này. Kết luận là gì: kiểu của MAX_LEN - 1 hoàn toàn xác định được bằng cách luật của C99, mà không phụ thuộc vào ngữ cảnh hay compiler.
|
|
|
Để chứng minh cho luận điểm của là MAX_LEN - 1 sẽ có kiểu là int, mình mời các bạn biên dịch và chạy đoạn chương trình sau, rồi giải thích giùm mình chuyện gì đã xảy ra:
Bài 8:
Code:
#include <stdlib.h>
#include <stdio.h>
#define MAX_LEN 0
int main(int argc, char **argv) {
unsigned int i = 1;
if (i < (MAX_LEN - 1)) {
printf("this can not happen, can it?\n");
}
return 0;
}
|
|
|
Các bạn có thể download C99 ở đây: http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf
|
|
|
nbthanh wrote:
Không biết "khác" là khác như thế nào? Giả sử như format vẫn đúng, nhưng input là thế này: '0xff' + "1" + '0x00' (tức chỉ định độ dài là 255 nhưng trên thực tế chỉ đưa vào có 1 ký tự) là có chuyện ngay smilie
Chỉ cần đúng format là được (1 byte length + label + 1 byte length + label...). Còn lại các field khác ra sao cũng được. Cách đưa input của bạn là đúng rồi đó, vấn đề là giải thích tại sao lại "có chuyện".
nbthanh wrote:
Nếu trên môi trường char là unicode 16 bit: '0xffff' + "...."
Mình nhớ đọc trong C99 thì kích thước của các type đều là implementation-defined nhưng mà mình không biết có môi trường nào mà char là 2 byte. Tất cả các môi trường mà mình biết thì đều có char là 1 byte. Nhờ bạn nbthanh đưa vài ví dụ môi trường mà char là 2 byte.
nbthanh wrote:
Còn nếu trên môi trường char là 1 byte thì strlen() trả về size_t, còn c là 1 byte thì strlen(name) + c sẽ trả về int hay short int? Chưa biết được vì còn phụ thuộc vào môi trường và compiler.
Trong khi đó MAX_LEN - 1 sẽ là kiểu int hay short int? Cũng...tùy vào compiler luôn
Mình nghĩ kiểu của biểu thức strlen(name) + c đã được quy định rất rõ trong C99, nó không phụ thuộc vào môi trường và compiler. Đối với MAX_LEN -1, sau bước preprocessing, nó sẽ trở thành 256 - 1, trong đó 256 và 1, theo quy định của C99, có kiểu là int, nên MAX_LEN - 1 sẽ có kiểu là int.
|
|
|
@OSato: ý là bạn nói đi tìm lỗi của những bài này là vô ích, bởi trong thực tế, nó phức tạp hơn nhiều?
Ờ thì tại mình nghĩ mình dốt, nên ráng tập làm mấy cái đơn giản này trước. Gặp cái nào khó quá, không làm được thì mình đành tìm trên Google xem bọn nó giải thế nào, rồi gửi lên đây lấy le vậy. Gì chứ mình xài Google tốt lắm.
À mà nói nhiều làm chi, chắc bạn OSATO toàn chơi cỡ mấy bài trên Phrack, nên mình dại mồm dại miệng nhờ bạn giải giùm mình bài số 7. Ông thầy cho về nhà từ học kỳ trước mà tới giờ mình vẫn chưa giải được. Ối bạn đừng chê nó đơn giản quá nên không thèm làm nha, mình tủi thân lắm huhuhu.
@rest: Nhân dịp...hết tháng 2, mình tặng tất cả các bạn một câu thế này của Mark Twain:
Mark Twain wrote:
It is better to keep your mouth shut and let people think you are a fool than to open it and remove all doubt.
|
|
|
Bài 7: xử lý Pascal string dạng như 9hvaonline3net0 (đây là dạng DNS domain name trong DNS packet, bài này ông thầy mình nói là sửa lại từ một real world vuln).
Để chạy thử theo đúng ý đồ của chương trình, các bạn phải nhập vào một Pascal string có dạng như sau: mỗi phần trong domain name sẽ được bắt đầu bằng một byte đánh dấu độ dài của nó; domain name kết thúc khi gặp một phần có độ dài là 0. Ví dụ như domain vnhacker.org thì các bạn phải nhập như sau:
./puzzle7 "`python -c 'print "\x08" + "vnhacker" + "\x03" + "org" + "\x00"'`"
your domain is: vinagame.com
Nói cách khác, để chỉ ra lỗi bài này, trước tiên các bạn phải giả sử là domain name nhập vào chắc chắn phải theo format này, tự vì các bạn nhập khác đi, chương trình nó sẽ chạy bị lỗi.
Code:
#include <stdlib.h>
#include <stdio.h>
#define MAX_LEN 256
char* get_domain(char* input) {
int c;
char name[MAX_LEN];
memset(name, '\0', sizeof(name));
c = (char)*input;
while (c) {
if ( strlen(name) + c < (MAX_LEN - 1) ) {
(char *)input++;
strncat(name, (char *)input, c);
input += c;
c = (char)*input;
strcat(name, ".");
} else {
fprintf(stderr, "something wrong happened!\n");
c = 0;
}
}
name[strlen(name)-1] = '\0';
return name;
}
int main(int argc, char **argv) {
if (argc != 2)
exit(0);
char* domain = (char *) get_domain(argv[1]);
printf("your domain is: %s\n", domain);
return 0;
}
|
|
|
|
|
|
|