Thursday, August 13, 2015

לפעמים, צריך שמישהו יזכיר לך את הדברים הפשוטים

Sometimes, someone should remind you of the simple things

לפני זמן מה, אחד הלקוחות שלנו ביקש לקבל גישה לסביבת בדיקות כדי לבצע בדיקות אבטחה. כמו שקורה תמיד במקרים כאלה, הלקוח קיבל גישה, שיחק קצת ובסוף התהליך שלח לנו דו"ח מפורט של כמה עשרות עמודים. כיוון שהיה מדובר בלקוח לא קטן, הדו"ח שלו קיבל עדיפות גבוהה יחסית ומצאתי את עצמי קורא אותו מוקדם בבוקר. 
הציפייה שלי הייתה לקרוא משהו דומות לדו"חות שראיתי בעבר - אוסף של אי-הבנות, בעיות זניחות שנמצאו ע"י איזה כלי אוטומטי כזה או אחר וכמה בעיות שאנחנו כבר מודעים אליהן ולא נמצאות באחריותנו (בפרוטוקול אליו אנחנו מחוייבים יש חולשה מובנית שכל הכלים האוטומטיים מוצאים) ובעיות שרלוונטיות רק לסביבת הבדיקות שניתנה ללקוח. מתוך הבעיות האלה, עשרה אחוזים יסווגו כחמורות, שלושים כבינוניות וכל היתר בחומרה נמוכה. 
אלא שהפעם עברתי על הבעיות שהם מצאו, ומתוך בערך שבעה ממצאים חמורים, הצלחתי לאמת חמישה, ועוד שישה או שבעה לא טרחתי לשחזר כי הם דרשו יותר עבודה והם היו מצליחים בוודאות גבוהה (יש כאן יותר משבעה ממצאים כי הם החביאו תתי-סעיפים בתוך כל ממצא).  ולא רק שכמעט כל הממצאים היו מדוייקים, כל אחד ואחד מהם גרם לי להרגיש קצת יותר שהם תפסו אותנו עם המכנסיים למטה. 
למעשה, הדו"ח הזה גרם לי להתבייש מספיק כדי לאסוף את כל הבודקים שמתעסקים עם המערכת שלנו ולהעביר להם הדרכה על איך לבצע בדיקות אבטחה בסיסיות. תוך כדי שאני מכין את המצגת, נזכרתי בשני דברים שכבר ידעתי (באמת שידעתי, אחרת איך הם הגיעו למצגת?): 
·           בעיות אבטחה הן רעיון שצריך להיתקל בו לפני שיודעים לחפש אותו לבד.
·           בדרך כלל,  יש קשר הפוך בין חומרת בעיית האבטחה לבין הקושי לנצל אותה.
מטרת המצגת, אגב, הייתה פשוטה - שכל אחד ואחד מהבודקים שמתעסק בתוכנה יקדיש קצת זמן לבדיקות אבטחה ויסלק את הבעיות הקלות. כך, כשאנחנו מזמינים מומחי אבטחה לבדוק את המערכת שלנו, הם לא יבזבזו זמן וידווחו לנו על השטויות האלה, אלא (בתקווה) יפעילו את הכלים והכישורים שאין לנו וימצאו בעיות קשות יותר לאיתור. 

במובן מסויים, זו גם מטרת הפוסט הזה - אתם בודקים משהו? יכול מאוד להיות שכדאי לכם להקדיש קצת זמן ואולי גם לחסוך למוצר שלכם בעיות כמו שהיו לפיאט. בסופו של יום, כל אחד יכול לבצע קצת בדיקות אבטחה - זה רק עניין של לדעת מה לחפש. 

עכשיו, להרחבה קצרה של שתי הנקודות שהזכרתי: 
ברוב המקרים, קל יותר לחפש בעית אבטחה אחרי שרואים דברים דומים
רוב מי שמתעסק קצת עם מחשבים שמע בעבר על  הזרקת SQL, וכנראה שגם על cross-site-scripting, מי שלמד קורס רלוונטי ידע לספר ש stack overflow זה לא רק אתר האינטרנט שכל המתכנתים מבלים בו שעות, אלא גם איום שעלול לתת לתוקף שליטה מלאה על המכונה שמריצה את הקוד שלנו.  בדרך כלל, מי ששמע על אלה יכיר גם את המונח CSRF גם אם הוא לא לגמרי בטוח איך לגרום לזה לקרות. 
מצד שני, מתי בפעם האחרונה הקדשתם מחשבה לדרך בה אתם מנהלים את הלוגים של המערכת? או לאופן המדוייק בו אתם שומרים את מפתחות ההצפנה? והאם טרחתם אי פעם לתהות אם יכול להיות שפיצ'ר מסויים שמפותח עכשיו הוא פתח להדלפת מידע? ואם אתם מתעסקים עם אינטרנט אבל לא ממש בקטע של אבטחת מידע - אתם זוכרים שאסור לסמוך על שום דבר שאתם חושבים שאתם עושים בצד הדפדפן? אחרי שמישהו יראה לכם באג כזה, לא תוכלו להתעלם מבעיות כאלה.

המקרים הראשונים, אלו שכולם מכירים וזוכרים, מהווים בדרך כלל את ההתקפות הברורות - מישהו מתעלל במערכת שלכם כדי לבצע פעולות שברור לגמרי שהוא לא אמור לבצע. 
המקרים האחרים, אלו שבחלק מהמקרים יהיה צורך להסביר למה בכלל הם בעיית אבטחה, יהיו בדרך כלל מאתגרים פחות מבחינה טכנית, אבל זה מביא אותנו לנקודה השנייה:
אם קל לנצל את החולשה, מדובר בבעיה חמורה יותר  
לכאורה, הדבר נוגד את האינטואיציה - לכולנו יושבת בראש תמונה של איזה האקר גאון שכותב שורות קוד סופר מתוחכמות וגורם לנזקים יצירתיים באפליקציה שלנו. בפועל, למרות שהתמונה הזו מייצגת איום אפשרי, יש לא מעט התקפות שמבוצעות על ידי גורמים מתוחכמים פחות. בנוסף, גם ההאקר היצירתי יחפש קודם כל את הכניסות הקלות, וכמו בבתים שמותקנת בהם אזעקה, אולי הגנב פשוט ילך לבית השכן, כי שם קל יותר ומסוכן פחות. 
אל תיתנו לתוקף מתנות בחינם.
אז מה מחפשים בזמן בדיקות אבטחה?
יש הבדל אחד משמעותי בין פרצות אבטחה לבין באגים רגילים, ההבדל הוא שברוב המקרים, אף אחד לא מנסה לגרום לבאג להופיע. לפעמים באג כזה יכול להיגרם ממימוש לא נכון של תנאי, לפעמים מדובר בהגדרה לא מושלמת או במצבי קיצון שנגרמים בעקבות עומס, אבל שני הצדדים לא מעוניינים שהוא יקרה. 
כשמדובר בחולשות אבטחה, הנחת היסוד של הבודק צריכה להיות שהתוקף יעשה כל מה שביכולתו כדי לנצל את החולשות האלה ולנסות להשיג דרכן משהו. כלומר, יש מישהו שמנסה לגרום לתוכנה שלכם לא לתפקד כדי לנצל את זה. 
לכן, הנחות כמו "אף משתמש לא יעשה משהו כזה" הן לא לגיטימיות. הנחת המוצא צריכה להיות שמולכם נמצא יריב נחוש ומוכשר שיעשה כל מה שאפשר כדי להשיג את שלו. בנוסף, לא רק שהוא נחוש ומוכשר - הוא גם מכיר את הקוד שלכם, יודע בדיוק איך המערכת בנויה ומכיר את כל פרצות האבטחה שיש בה. 

כמו שכתבתי בתחילת העמוד, כל אחד יכול לבצע בדיקות אבטחה, וגם אם הן לא יחסמו את התוקף המיומן להחריד שהזכרתי, הן יסננו החוצה חלק גדול מהתוקפים המיומנים פחות, ימנעו מביקורות אבטחה למצוא ממצאים מביכים וישאירו למומחה האבטחה שהחברה שלכם שכרה כדי לבצע בדיקות חדירה זמן לחפש את החולשות המסובכות יותר. 

אז הנה כמה דברים שאפשר לעשות, כמעט בחינם: 

  1. בצעו פעולות חוקיות, אבל נסו לעקוף כל מיני הגבלות - גם הגבלות ייחודיות לתוכנה וגם הגבלות שנובעות מתוך היגיון.למשתמש אסור לראות דף מסויים במערכת, ביטלתם את הלינק מהדף הראשי אבל הלינק מדף FAQ עדיין מוביל לשם? בעיה.משתמש יכול לבקש איפוס סיסמה ולספק כתובת דוא"ל שאינה כתובה במערכת? בעיה.
  2. כשאתם מחפשים מידע רגיש, סרקו את כל הפלט, לא רק מה שמוצג למשתמש מול העיניים.אתם מדפיסים סיסמאות של משתמשים לקבצי הלוג? בעיה.יש מידע שאתם לא רוצים להציג למשתמש שגולש לאתר שלכם והמתכנתים חושבים שלהגדיר את השדה כhidden זה טוב מספיק? עדיין אפשר לראות אותו בעזרת view source
  3. השתלטו על כל מקורות הקלט של האפליקציה שלכם: המשתמש הקליד משהו במסך? ומה אם זה באורך של חמישים אלף תווים? או מכיל קוד HTML?ומה קורה אם שרת של חברה אחרת איתה אתם עובדים מתחיל להחזיר תשובות מוזרות? או אם מישהו שיחק עם אחד מקבצי הקונפיגורציה  - האם הוא יכול להשיג משהו בעזרת זה? או להפיל את המערכת?
  4. בדקו מקרי שגיאה ונסו לנצל אותם.
    האם הודעת שגיאה חושפת מידע שהיא לא צריכה לחשוף?
    האם כשל בתקשורת עם שרת LDAP מאפשרת למשתמש שכבר נכנס למערכת לבצע פעולות שהוא לא מורשה לבצע?
    מערכת ההפעלה (או JVM, אם משתמשים בג'אווה) עלולה להדפיס לקובץ את הזיכרון של תהליכים שקורסים  - האם ניתן למצוא שם מידע רגיש?
והכי חשוב לזכור - בדיקות אבטחה הן עניין של צורת מחשבה יותר מאשר כישורים טכניים ספציפיים.
----------------------------------------------------------------------------
 A while ago, one of our customers requested access to a testing environment in order to perform some security testing on our system. As is usually the case, he got the requested access, played a bit with our system and in the end sent us a lengthy report detailing all of the findings.
Since this was a big customer, providing an initial response to the report was given high priority and I found myself reading the report early in the morning.
My expectation was to read a report very similar to other such reports I read in the past: a collection of misunderstandings, some negligible problems found by an automated tool scanning our system, some problems we are already aware of and can do nothing about (In the design of the protocol we are implementing there is a security issue that most automated tools find) and some issues that exist only in the test environment. Out of these, about 10% will be marked as "high", 30% more will be labeled as medium, and the rest are low severity issues.
This time, however, as I went over the seven high findings I was able to reproduce five issues and I didn't bother reproducing six or seven more issues  since they required a bit more work and I was certain they would be just as easily reproduced (you might have noticed that this sums up to more than just seven findings, this is because the customer was kind enough to group issues and detail them in sub-sections).
Worse: not only most of the findings were accurate, almost each and every one of them made me feel a bit more as if we were caught with our pants down.
In fact, this report made me ashamed enough to set up a meeting with all of the testers working on our system and give them a short lecture on security testing.
While I was preparing the presentation to the meeting, I recalled two things I already knew (Honestly, I knew those things. How would they otherwise end up in my presentation?):
·        Before being able to look for security issues yourself, you have to encounter the idea for that type of vulnerability.
·        Normally, there is an inverse connection between how simple is a security vulnerability and how severe this vulnerability is.
The goal of the presentation was simple: to have every tester in the room to invest some time doing security tests as part of the feature testing and get rid of the easy problems. This way, when we hire security expert to test our system, they won't waste time reporting the trivial problems but will (hopefully) put to use the tools and skills they have and we don't in order to find stealthier problems.
In a manner, this is also the purpose of this post: are you testing something? Perhaps you should invest some time to security testing, and maybe even avoid problems like FIAT had. At the end of the day, everyone can perform at least some security testing, it is only a matter of knowing what to look for.
After claiming that, I want to elaborate just a little bit on the two points I mentioned before:
Most of the time, it is easier to look for security problems after seeing similar things.
Probably almost anyone that knows just a tiny bit about computers has heard about SQL-injection, and it is very likely that the term "cross-site-scripting" will be familiar as well. Those that took a relevant course (even a basic one) will know that stack-overflow isn't just a website where programmers spend hours, but also a threat that could potentially give the attacker full control on your computer. Most of the time, they will know the term CSRF, even if they will be a bit sketchy on the details of how to exploit it.
On the other hand, when was the last time you stopped to examine the way you manage your cryptographic keys? Have you ever thought to check your application log files for usernames and passwords? Did you ever consider that the feature being developed right now might leak sensitive information to unauthorized personas? If you are testing a client-server system such as a website, do you remember that you cannot rely on any validation made in the client side?  After someone will show you such issues you will not be able to ignore these things.
The cases in the first group of attacks, those that everybody remembers, are cases of obvious, straightforward attacks. It is a clear case of a user doing things he's not allowed to do.  The second group items, however, might be little bit vague. In some cases you will have to argue your case to explain this is even an issue. Those parts are usually less technically challenging – which brings us to the second point:
If the vulnerability is easy to exploit, the problem is more severe
At first glance, this is counter intuitive. We are all used to think of the lone genius hacker writing super sophisticated attacks against our systems and causes creative damage to it. In practice, while this scenario is a viable possibility, there are much more cases of attackers with limited resources and knowledge. Moreover - even this creative hacker will start by looking for the easy targets (either since they will provide him with sufficient power, or they will be leveraged in the next attack), and just like a thief who sees that your house has an intruder alarm, he might go over to the neighbor's house since the profit there will not be as risky and will require less effort.
Don't provide the attacker with free gifts.
So, what to look for while performing security tests?
There is a significant difference between regular bugs and security vulnerabilities: in most cases, no one wants a regular bug to manifest. In most cases it will be at least a bit inconvenient to the user that only wants to use your application to the end it was built for. The bug might be caused by a faulty implementation of the logic, by some tricky race-condition or even by problematic requirements, but it is safe to assume the user will try to avoid bugs (except if they provide some cool outcome, but even then, the user isn't being malicious).
While performing security testing, this assumption is thrown out of the window. The basic assumption is that an attacker will do anything within his power to exploit those weaknesses to his own ends. This means that there is someone that will actively try to make your system fail in order to take advantage of this. This means you cannot make assumptions such as "no user will ever do this". The assumption in security testing is that you are facing a skilled and determined adversary. Furthermore, on top of being very good at causing damage, you also assume the attacker knows your application inside out, alongside with any security vulnerability you have.
As I wrote before – anyone can perform security tests, and even if they will not block the super-complex attacks, they will deter and filter out a large number of the less skilled attackers, will save your company from embarrassing security audit results and leave more time for the security tester your company hired for a short contract job to find effective findings and look for the more complex issues.
So, here are some ideas you can implement with almost zero cost (zero but the time you invest):
1.    Perform legitimate actions, but try to bypass boundaries and limitations – both limitations defined in your product and those that are just common sense.
a certain type of user shouldn't be able to access some page, and you removed  the link from the main page – did you also remove the link from the FAQ section? That's a problem.
A user can ask for reset password and provide his own, unregistered email address for the recover password link? This might be a problem.
2.    When searching for sensitive information, look at every output channel, not only what is visible to the simple user.
Are you printing passwords to the debug log files?  That's a problem.
There is something you don't want the user browsing to your website to see and the developers thought it would be enough to mark the element visibility as "hidden"? you can still see that by using "view source" functionality.
3.    Take control of every input channel to your application.
The user can type something on the screen? What if it's a 50 thousand characters long text? What if it contains HTML meta characters?
And what happens if a server of a third party you are using starts to return funny responses? Or if someone edits a configuration file? Can this crash the system?
4.    Look for error cases and try to leverage them.
Does an error message reveal more information than it should?
Will a failure in communicating with the LDAP sever enable a logged in user to perform actions he's not allowed to perform?
When a process crashes, the OS (or JVM, if you're using java) might print that process's memory to a file, does this file contain sensitive data?

And on a final note, it is important to remember: Security testing is more a mindset than it is a set of specific technical skills.  



No comments:

Post a Comment