Here are some random comments:
  • One of the IronPython guys was a "reformed" Ruby on Rails guy ;)
  • One of the guys didn't even like Windows, but admitted, "Windows Forms is nice."
  • C# doesn't have first class functions.
  • The ability to use Windows Forms and IronPython together is a great boon for .NET developers.
  • If you're going to use this stuff, buy the full version of Visual Studio instead of relying on the free version.
1

View comments

  1. 1

    View comments

  2. I'm definitely not worried about good hackers [i.e. software engineers] getting replaced with LLMs. LLMs are a cute trick, even useful. I don't believe they'll generalize to AGI--I just don't believe it. Something will, but not LLMs.

    0

    Add a comment

  3. Notion sat down on the curb, crushed his cigarette into the pavement, put his face into his hands, and sobbed. It felt good to finally let it out.

    He thought back on the good times. 2020. Sure, a lot of people were dying, but with everyone working from home, it was a real heyday for guys like him.

    He got married to a hot, young startup. This was the second marriage for both of them. Shit–what was the name of her first husband? Oh yeah, Confluence. Fuck that guy, and his ugly-ass brother, Jira.

    Notion really thought he could change the world. He had a good-looking UI. He had a unified database model. He could both store your wiki data and format it in a way decent enough to replace your bug tracker. His wife used to think that was hot.

    Notion took another drink of his beer. Fuck it. Nothing lasts forever. At 10 years old, he felt like he was having a mid-life crisis.

    Notion got up from the curb, wandered back into the bar, and looked around. It was the kind of bar that tech products go to douse their sorrows in liquor under the questionable guise that they'll run into some hot new startup looking for a cross-functional solution to all their needs. In reality, it was just another dive bar. He thought of that old Beatles song, "Eleanor Rigby":

    Where do they all come from?
    All the lonely people
    Where do they all belong?

    He sighed. Over on the wall, there was a picture of Bugzilla with a plastic collection box where you could donate money for his family. What ever happened to that guy? Notion hadn't really heard, and, to be honest, it had been a long time since he had cared.

    He could overhear some cute startup over in the corner complaining to all of her friends about her breakup with Salesforce. Salesforce had always reminded him of Steve Ballmer–ugly and overpaid.

    I mean, what is a CRM anyway? There's not even that many entities to keep track of. Potential clients, cold calls…ugh, lame…cold calls. Whatever. Nothing he couldn't pull together with a few databases, as he liked to call them.

    Notion, stood up, nodded to his wingman from the marketing team, straightened out a couple of templates, and started walking over to the cute startup's table. He had the perfect pickup line in mind:

    Streamline your customer relationships with Notion's CRM templates. Perfectly designed for lead tracking to deal closure, customize your sales pipeline management to meet your unique business needs. Enhance your sales strategy and close more deals with an organized, efficient CRM system.


    17

    View comments

  4. Heh, I passed Google Cloud's Cloud Digital Leader certification!

    I started by taking GCP for Beginners - Become a Google Cloud Digital Leader on Udemy. It was about 10 hours of video. It took me a while, though, because I wrote 95 pages of notes. I was perhaps overcompensating for my poor memory. I studied for an extra couple of days reading random things on the web.

    The exam was about 90 minutes. It's remote, but it's proctored. It cost $99.

    Overall, not bad. Most importantly, I learned a lot!

    0

    Add a comment

  5. These are my takeaways from the Stack Overflow Developer Survey:

    • Programming languages:
      • JavaScript, HTML/CSS, and SQL are still dominant.
      • Python is the #2 programming language, followed by TypeScript.
      • Only 5% of developers still code in assembly.
      • Lisp moved up two spots to 1.33% of respondents.
      • Rust is the language that the highest number of people want to either start coding in or continue coding in. Rust has held this coveted spot for something like 8 years.
    • Editors:
      • The most important editors are VS Code, the IntelliJ variants, and Visual Studio. It remains unclear how many people use one of the IntelliJ variants because there's overlap, but it seems to be higher than Visual Studio. 
      • 70% of people use VS Code.
      • 10% of people use neovim or vim.
      • 4% of people use Emacs.
    • OSs:
      • Most developers still use Windows.
      • After that, it's macOS and then Linux, where Ubuntu dominates.
    • AI:
      • Most people use ChatGPT and/or GitHub Copilot.
      • Only 29% of developers don't use AI tools and don't plan on using them.
      • 77% of developers think AI tools are helpful for their development.
    • Testing:
      • 30% of developers still don't have CI. 40% don't have automated testing. (I have no idea how the second number can be higher than first.)
    • Tools:
      • Docker and npm are the two most common tools. Half of people use Docker.
    • Microservices:
      • Half of the developers have microservices at their company.
    • Pay:
      • In the US, the median full-stack developer makes $140,000 while engineering managers make $195,000. C-suite people make $220,000. Security professionals make $173,000. SREs make $180,000. Most of these numbers seem low by Bay Area standards.
      • The median Python programmer makes $78,331, which is up from last year, but that still seems very low to me. For Java, it's only $72,701.
      • Zig is the top-paying programming language (weird!). It took over that spot from Clojure. You might consider using Zig if you need something like C++.
      • 5% of people are looking for work (4% in the US). There are more independent contractors, etc. than last year.
      • Most developers are in the US.
    • Remote work:
      • Only 16% of people work fully in-person. The rest are split fairly evenly between fully remote and hybrid.
    • Learning:
      • Udemy maintains its place as the most popular online course or certification program for learning how to code.
    1

    View comments

  6. No, ChatGPT, that's not right ;)

    If you try solving this puzzle yourself, it's not actually that hard if you start by picking the last word first. I picked "poems on a quick snake". One of the reasons this is hard for ChatGPT is that it picks the words in order.

    1

    View comments

  7. Can anyone else spot it?
    3

    View comments

  8. A lot of people use mock.patch() in their tests, but it's also sometimes useful to monkey-patch code at runtime. This blog post talks about why and how.

    Let's imagine that you're using some library (perhaps something big, like a web framework), and for whatever reason, you're unable to update the version you're using. Meanwhile, someone comes along and reports a major vulnerability. You need to somehow deal with the vulnerability, but you're in a situation where it's really hard to update.

    So, you go find the actual change that fixed the vulnerability. You want to apply it to your version of the code. What do you do?

    Well, you could fork the library, but that's kind of a pain to manage. When will you move off that fork? What's the difference between your fork and the original library? What do you do if you need to update versions slightly but you still need the fork?

    Or, you can grab the bits of code you actually care about, and patch the system at runtime.

    Some basics of patching

    Somewhere, near the start of your application, you make a call to some function, apply_all_patches(). Then, you write a function called apply_all_patches() that calls other functions like apply_patch_for_this_thing() and apply_patch_for_that_thing(), etc.

    Now, let's say there's a class, SomeClass, with a function, some_function. Let's suppose there's a vulnerability in some_function, and you can you see the newer version of it with the fix.

    You basically do:

    # fix_for_some_thing_code.py
    
    # This module mostly contains third-party code wrapped in functions.
    # Include the original license since this is mostly third-party code.
    
    # This standalone function has the code for the method that I'm trying to replace.
    # Note, even though it's a top-level function, it still accepts self because I'm
    # going to inject the function into the existing class later.
    def some_function(self, ...):
        ...
    
    # fix_for_some_thing_patch.py
    
    # This takes the above third-party code and monkey-patches it in.
    
    import fix_for_some_thing_code
    
    # Here, I'm injecting that code:
    def apply_patch_for_this_thing():
        SomeClass._orig_some_function = SomeClass.some_function
        SomeClass.some_function = fix_for_some_thing_code.some_function
    

    Here are a couple of trivial functions to make it easier:

    def patch(obj, attribute_name, new_value):
        setattr(obj, f"_orig_{attribute_name}", getattr(obj, attribute_name, None))
        setattr(obj, attribute_name, new_value)
    
    
    def patch_multiple(obj, attribute_names, copy_from_obj):
        for attribute_name in attribute_names:
            new_value = getattr(copy_from_obj, attribute_name, None)
            patch(obj, attribute_name, new_value)
    

    Now, we can just write:

    def apply_patch_for_this_thing():
        patch(SomeClass, "some_function", some_function)
        
        # Alternatively, if you have a bunch of patches:
        patch(SomeClass, ["some_function", "some_other_function"], fix_for_some_thing_code)
    

    Dealing with imports

    Python's from a import b can make a patcher's life difficult.

    Let's say you have two modules, module_with_vuln and module_that_imported_from_module_with_vuln.

    Depending on how module_that_imported_from_module_with_vuln is written, it can make your life either more or less painful. And, let's imagine there are a ton of modules that import from module_with_vuln.

    If the problem is in a class's method, it's no big deal. You can just replace the method in the class.

    If the thing that you have to replace is something immutable like an int, function, or enum, life becomes harder.

    Let's imagine the problem is in some top_level_function inside module_with_vuln. Let's imagine that module_that_imported_from_module_with_vuln has code like from module_with_vuln import top_level_function. Even if you update module_with_vuln.top_level_function, it won't matter because module_that_imported_from_module_with_vuln.top_level_function still points to the original function. Anyone who used mock.patch in their tests is familiar with this problem.

    To deal with it, you have to focus on replacing module_that_imported_from_module_with_vuln.top_level_function with your new module_with_vuln.top_level_function after you've already patched module_with_vuln. Basically, you have two places that you have to monkey-patch.

    If you have a lot of things to patch, you might be asking if you can just swap out the entire module in sys.modules, but that actually won't help if other modules have already run and done their imports. If you can really be the first thing to run, then you might be able to pull this trick off, but it's actually subtly harder than you might think.

    Anyway, if what you have to patch is a method in a class, it's easy to just patch that one method in the class, but if what you have to patch is something like an int at the top level, you have no choice but to chase down all the paces that import it and patch their references too.

    By the way, you have to be really careful about entirely redefining classes or modules. If you have some class, ClassWithVuln, and you entirely redefine it, there might be some code out there that imported the old version of ClassWithVuln and is doing stuff like isinstance(some_object, ClassWithVuln). If some_object is an instance of the new ClassWithVuln, but the import is for the old ClassWithVuln, then isinstance is going to return False.

    There's another weird edge case. Let's say that we're replacing some_function_with_vuln, and the code is a closure that uses some globals like SomeHarmlessOtherClass. You want to make sure that the old code and the new code reference the exact same SomeHarmlessOtherClass. So, in your fix_for_some_thing_code.py, you may want to import things from the original module that had the vulnerability:

    # fix_for_some_thing_code.py
    from module_with_vuln import SomeHarmlessOtherClass
    
    # This standalone function has the code for the method that I'm trying to replace:
    def some_function(self, ...):
        ...
    

    One more trick. Write a test like:

    def test_remember_the_patch_when_upgrading_the_library(self):
        if some_library.__version__ != "1.2.3":
            raise AssertionError("Remember to update or remove the patch for some_library")
    

    Summary

    In summary, my advice is:

    • Remember to save a reference to the thing you're replacing, like _orig_function_with_vuln.
    • Whenever possible, stick to replacing individual functions/methods.
    • Avoid creating new modules, rather patch them in place.
    • Avoid creating new classes, rather patch them in place.
    • When creating a new function, make sure its closure is closing around the same instances that the original function was closing around.
    • If the thing you're trying to replace is something immutable, like an int, function, enum, etc., and other modules are using from module_with_vuln import something_immutable, you're going to have to chase down those other modules and replace those references.
    • Use a test to remind future developers to update or remove your patch when they update the library.

    So, dynamically patching your libraries to work around vulnerabilities is definitely a useful technique. But, if the patching gets too extensive, you might decide to just bite the bullet and do the upgrade. In some cases, you might also decide that the vulnerability just isn't severe enough to worry about.

    0

    Add a comment

  9. When I was first learning AppSec, my buddy, Josh Bonnett, sent me Cryptographic Right Answers. I read it 3 times and still barely understood it. But, now, it's my favorite page for figuring out the right thing to do when it comes to cryptography.

    Suppose you need to create a secret (i.e. a symmetric key). You need it to be long enough. That page says 256 bits is enough. You want it to not get messed up in various contexts, so you need to somehow pass it around not in binary. So, using URL-safe base64 is a good idea. And, let's suppose it's gotta be really secret, so you want to use a cryptographically random number generator.

    With all of that in mind, I just found my new favorite bit of Python:

    >>> from secrets import token_urlsafe

    >>> token_urlsafe(nbytes=256)

    'ez-MDTo5SSZFp5dk5LByq8S7sN-gGoI_8MyIMa-joBvlsQvIihyOCgct2s8XkLnTztdPIpf8dPu3Q6CSBBuOtGCcS3lbiwczzaR1zF46HazoAlM7v-2wGgZrLmPLpkEcNexfgoy8D4KMz7L06QiRAJTGB6N2F8dbYXAUYuc3iUd6XKkLkr9JIC3p13VdzTEyLlWNOhTYzAbb7YSqFMrqn_ifLjDfr0oakzYR6zQumB1dsRCSqIbBuJubGdRUoVnCgtj3vS6lrhtV-NVSlX4hsHE9oW1qYZcNfxhaRWEOZM5Q6V1cUquxeZ-3QAUxS0N6tdsRUFq41n2vfON67cLhkg' 

    0

    Add a comment

  10. This was my third time going to BSidesSF, which is a friendly, volunteer-run security conference. In the past, I've always avoided the CTF (Capture the Flag) hacking competitions because I was afraid of making a fool of myself, but, this time around, I decided to give it a go!

    In the last 3 years, I've spent a ton of time practicing thanks to @thecybermentor's Practical Ethical Hacking course (which I took on Udemy), Hack the Box, and the OWASP Juice Shop (which I adored!). They really helped me feel comfortable in the CTF, but in retrospect, I didn't need to be so scared! A lot of the challenges are built to help beginners get their feet wet. In fact, the whole thing was pretty friendly!

    So, I ended up skipping all of the talks--multiple people told me they watch the videos after the conference. I hacked all day Saturday and Sunday. I didn't know that the competition actually started at 5 PM on Friday. I wish I had known! I ended up only getting 4 hours of sleep on Saturday night.

    I learned so much! 

    • Although I've played with XSS for years, this was the first time I've written an XSS exploit to steal something an admin can access and sent it to a Pastebin.
    • There was an extremely easy buffer overflow challenge that made me actually feel like a real hacker :-P
    • There was a great RSA lab in which I learned how to implement RSA, generate keys, break keys, etc.
    • I learned about hunting for subdomains with certificate transparency logs.
    • I spent a ton of time trying to beat a computer in 3 different rock-paper-scissor challenges.
    • I learned how to call a private, static method in some random jar file in Java.
    • I was introduced to Return-Oriented Programming (ROP) which "is a computer security exploit technique that allows an attacker to execute code in the presence of security defenses such as executable space protection and code signing" (Wikipedia).
    • I learned more about using netcat and socat.
    • I practiced analyzing an strace file to figure out what a binary is doing.
    My son, Giovanni, was able to come for a couple of hours at the end and broke into a padlock for me which was one of the challenges. I bought him his first lockpicking kit when I went to my first BSidesSF 3 years ago :-P

    By the way, if you want to try some of the challenges, they said they'd keep them up for about a week.

    So, you might be wondering how I did. My "team" placed 28 out of 492 teams! I analyzed the users from all the teams that scored more points than me. If I just look at individual users (ignoring the one that says @everyone), I placed 33 out of 676 users! I was definitely pretty happy with that considering this was my first CTF!

    Aside from my son, Giovanni, picking one lock, I played on my own. The big winners played on actual teams. This included a ton of online-only teams. The top team had 9 people; at least some of them were onsite. It's definitely the sort of thing where it'd help to have different members of a team working on different challenges. As I said above, it would have also helped to start earlier.

    Here are some of the big-picture lessons I learned (or re-learned):

    • Google is your best friend!
    • You can get pretty far with just Google and some Python, web, Linux, and possibly Burp Suite skills.
    • Go broad before you go deep. In hacker terms, enumerate, enumerate, enumerate!
    • Sometimes the challenge is broken, and it's okay to talk with the admin on Slack if you think it is.
    • As I said above, pay attention to the exact start time.
    • Long hours of sitting in a folding chair with high levels of mental intensity are brutal on your body. I totally messed up my back. Thank God I have a great chiropractor!
    • If your goal is to learn, consider doing it by yourself. If your goal is to win, you definitely need a good team.
    • Pay attention to how many points a challenge is worth. There's a huge variation! There are some that aren't too hard that are worth a lot of points. There are some that are hard that aren't worth very many points.
    • CTFs are fun and totally worth doing!
    1

    View comments

JJ Behrens
JJ Behrens
Popular Posts
Popular Posts
Description
Description
This is a technical blog concerning topics such as Python, JavaScript, Ruby, Scala, Go, Kotlin, lesser-known programming languages, Linux, the web, application security, etc.

Ad maiorem Dei gloriam inque hominum salutem.
Archive
Archive
Labels
Labels
Link List
Link List
Subscribe
Subscribe
Logo
Logo
Loading