MOVEit was hacked badly and what we can learn from that

Back to 2023, there were critical security incidents happened in a row, that caused massive data breaches from hundreds of organizations and exposed data belonging to tens of millions of people worldwide. All of these incidents were from a same Zero Day security flaw in a File Transfer software, named MOVEit, and are used by several large companies. More importantly, the flaw was known as SQL Injection – one of the most ancient flaw that hardly exists today (even in 2023) thanks to security awareness among developers is increased and adoption of modern frameworks & database libraries in software developments.

1. What is MOVEit, firstly ?

MOVEit is a Managed File Transfer (MFT) software that helps organizations securely transfer sensitive files between employees, business partners, customers, and internal systems. Large organizations, including banks, healthcare providers, government agencies, and enterprises, commonly use MOVEit to exchange confidential data such as financial reports, payroll files, customer records, and medical information.

MOVEit provides a web-based interface (running on Microsoft IIS) that allows users and applications to upload, download, and manage files. Most of the application’s business logic is written in C#, and data such as user accounts, sessions, permissions, and file information are stored in a Microsoft SQL Server database.

2. What is SQL Injection ?

SQL injection is a security flaw that commonly happened with web applications in the past when developers tended to use raw SQL statements and concatenating user’s inputs. As a result, when a user submit a malformed input with SQL syntaxes in it, they can inject that SQL syntaxes to the raw SQL statement and get executed by the server. This malformed SQL syntaxes is called SQL Injection payload.

For example, suppose a login page checks a username using the following query:

SELECT * FROM Users
WHERE username = '<user_input>';

If the application inserts user input directly into the query, an attacker could enter a username like so:

' OR 1=1 --

The resulting SQL statement becomes:

SELECT * FROM Users
WHERE username = '' OR 1=1 --';

Because 1=1 is always true, the query may return all rows, potentially bypassing authentication or exposing sensitive data.

3. How did SQL Injection happen in MOVEit ?

MOVEit is not an open source project so there is no source code to examine publicly. According to sources of news, the vulnerability was a classic SQL Injection flaw. There is a Proof of Concept (Poc) here: https://github.com/errorfiathck/MOVEit-Exploit/blob/main/CVE-2023-34362-exploit.py , but to test it, we need a vulnerable MOVEit server – which is no longer downloadable.

After data breaches, MOVEit’s owner already released patched versions. Many components of MOVEit are written in C# programming language, which makes it easy for “reverse engineering” by using decompiling tools such as dnSpyEx, ILSpy or IDA. If you’re unfamiliar with this term yet, Reverse Engineering is techniques that translate computer programs (e.g. .exe files on Windows) back to its source code, as close as possible. According to researchers who had the vulnerable MOVEit version, after compared with the patched versions, what they found was not a simple, direct SQL Injection like on above example, but an exploit chain in which several seemingly harmless features could be combined in an unexpected way, and then open a SQL Injection flaw.

To simplify, this is how it happened:

  1. The attacker send a HTTP request: POST to /moveitisapi/moveitisapi.dll?action=m2 with headers X-siLock-Transaction: session_setvars and multiple X-siLock-SessVarN headers to create arbitrary session variables on the server.
  2. One of those X-siLock-SessVar values contains the SQL injection payload
  3. The attacker then sends another HTTP request to guestaccess.aspx (a normal form submission) which causes server-side code to read those session variables and use them when building & executing SQL.
  4. Because the session variable values are not sanitized, the SQL Injection payload is concatenated to the SQL query on server and execute.

This vulnerability centers on the /MOVEitISAPI.dll endpoint. The application trusted and stored values supplied in HTTP headers during one stage of request processing, but later reused those same values to construct SQL queries without validating or sanitizing them again. As a result, hackers can run any SQL statements on server by adjusting payload in HTTP headers. In another words, they can access to the database with full privilege. And that is why there were critical data breaches like so.

4. How to defend against SQL Injection ?

SQL Injection has been a well-understood vulnerability for decades, and modern development tools provide effective ways to prevent it. In most cases, SQL injection occurs not because secure solutions are unavailable, but because developers ignore them or make incorrect assumptions about the trustworthiness of data. The following practices can eliminate the vast majority of SQL injection vulnerabilities.

4.1. Avoid String Concatenation When Building SQL Statements

The most important rule is never construct SQL statements by concatenating strings with untrusted input. No matter where the input comes from: a form, URL, HTTP header, cookie, session, or another internal components, it should never become part of the SQL syntax.

Unsafe example:

String sql =
"SELECT * FROM Users WHERE username = '" + username + "'";

If username contains SQL syntaxes, the query itself will be modified, allowing an attacker to inject other SQL statements.

Instead, always use parameterized queries (also known as prepared statements), where the SQL statement and its parameters are sent separately to the database engine.

Safe example:

SELECT * FROM Users WHERE username = @username;

With parameterized queries, the database treats @username as data rather than executable SQL, preventing attackers from altering the query structure.

4.2. Do not re-invent the ORM

Modern software development frameworks already provide mature database access libraries and Object-Relational Mapping (ORM) frameworks that automatically use parameterized queries for most database operations. Examples include Hibernate, Django ORM, SQLAlchemy, and many others.

Developers should avoid writing their own SQL generation logic unless there is a reason to do so. Re-implementing database access often introduces subtle security bugs, such as incorrect escaping, improper input validation, or trust-boundary violations that existing ORM frameworks have already solved.

Even when raw SQL is necessary for performance or complex queries, it should still use parameterized statements instead of string concatenation.

In general, the safest approach is to rely on well-tested database libraries and ORM frameworks rather than attempting to build custom query-generation code. Mature frameworks have been reviewed, tested, and improved over many years, making them less likely to introduce SQL injection vulnerabilities than homemade implementations.

5. What can we learn from this ?

5.1. Don’t Trust Internal Data Blindly

Data should be trusted based on its origin, not based on where it is stored.

Although the exploit chain here was technically sophisticated, the root causes is much more simple: forget sanitizing inputs. This forgetting here stems from the trust based on where data is stored: internal session variables. Trusting data because it is “internal” create a trust-boundary violations that are difficult to identify during code review.

5.2. Old flaws still exist

Today, SQL injection is far less common than it was in the early days of web development. Modern frameworks, ORM libraries, parameterized queries, and increased developer security awareness have significantly reduced its occurrence. However, the MOVEit vulnerability again demonstrates that even mature commercial software can still contain classic vulnerabilities when subtle coding mistakes bypass these built-in protections.

Security is not only about defending against the newest attack techniques. Many high-impact incidents continue to result from well-known vulnerabilities that developers assume have already been solved.

5.3. Close-Source softwares are Open-Source softwares, at some extent

A common misconception is that private software is more secure because its source code is not publicly available. In reality, compiled applications can often be reverse engineered with remarkable accuracy. Therefore, software security should never rely on keeping the source code secret. Instead, it should be built on an assumption that a hacker may have a way to understand how it work.

đź“© Join Our Newsletter Today
Subscribe here👇

Leave a Reply