
Curious Perversions from the IT World - 4
- Transfer

Site The Daily WTF for 15 years collecting a funny, wild and / or the sad stories of the IT world. I translated several stories that seemed interesting to me. All company names and names have been changed. Previous issues can be found under the label " curious perversions ."
The first story. End of the month
[Original]
If you ask a design engineer whether it is safe to walk across a bridge, he will be happy to tell you how reliable the bridges are, how mathematics work in them, how far we have come in matters of construction safety. After talking with him, you will get the impression that not a single bridge on Earth will ever fall apart. But if you ask the software development engineer about the banks, then you will most likely be horrified, and with a 50/50 probability convince yourself to invest all the money in bitcoin. Banks are notorious for their bad decisions when creating software - not because these decisions are disgusting, but because most people assume that banks are more accurate and careful about security.
Katoworks at Inibank, where a commercial product called T24 is used as the core of the banking system. The T24 system is used by hundreds of banks around the world. It can be customized to a wide range of banking solutions. As with most custom packages. There are programmers who specialize in writing code for it, and consultants who help banks with major updates.
Inibank staff was busy, so the bank invited a consultant to participate in a special project. At the end of the working day, the bank carried out the completion process, which is necessary so that all the money goes where it was directed, all the necessary output data are recalculated, and all the required reports are executed. At banks, this process also changes the system date to the next business day. That is why when you do online banking on Sunday, not a single transaction begins to be processed until Monday morning. The consultant had to create a new report that would be executed during the completion process and included additional processing if the date corresponded to the end of the month.
Kato showed the new consultant how the bank sets up end-of-day reports. “See, we have global variables for the previous working day, for today, and for the next working day. They have the format YYMMDD to make it easier to work with. "
“Yeah, yeah, got it. I get it. What format are they in? ”
"... Uhh ... I can only assume that this is the year, month and day."
“Yeah, yeah, okay. Excellent. Then I get to work. ”
After this conversation, Kato had a bad feeling about this. but he tried to get rid of him. The consultant said that everything is set up and ready. He knows exactly what he’s doing, right? Kato threw this out of his head and stopped worrying until the time for code review and he found such a pearl:
TH.DATE = R.DATES(EB.DAT.NEXT.WORKING.DAY)[1,6]:"01"
CALL CDT('ES00',TH.DATE,"-1C")
WTODAY = OCONV(DATE(),"DY") : FMT(OCONV(DATE(),"DM"),'R%2') : FMT(OCONV(DATE(),"DD"),'R%2')
IF TH.DATE EQ WTODAY THEN
Let us explain briefly what is happening here:
- Take the next business day and change the day to 01 to get the first day of the month.
- We change this date by subtracting 1 calendar day on the calendar of Spain.
- We take the date from the server and translate it into the format YYYYMMDD, calling the Date command three times.
- If the date calculated in step 2 is equal to the date calculated in step 3, start the process.
Well, actually ... it works. Mostly. Unless for some reason, the end of the day does not happen after midnight on the penultimate day of the month - and this is not so rare. In this case, the code will mistakenly think that this is the last day of the month, and will start creating the report. Which goes well with another problem: if the same thing happens on the last day of the month, then creating the report will not start by mistake. And the best bug: if the last day of the month turned out to be Sunday, then the server’s calendar will never be installed on it, because it skips non-working days.
Speaking of non-working days: since Inibank is located in the USA, there is no reason to use the Spain calendar. Yes, the months and weeks will be the same, but in the Spanish software calendar you need to specify bank holidays in the USA, otherwise the program will continue to work. Finally, as if all this wasn’t enough yet, a triple Date call means that there may be disagreements when starting at midnight: the month value is requested before midnight, and the day after it.
Kato added a comment, suggesting a way to change the code:
IF R.DATES(EB.DAT.TODAY)[5,2] # R.DATES(EB.DAT.LAST.WORKING.DAY)[5,2] THEN
Five minutes later, the consultant walked to his desk. “What does this edit mean?”
Kato was not in a mood to argue at that moment. “Your code is broken, friend. All this is not necessary. "
“I see, I see. This is actually just a standard operating procedure for our industry. Anyway".
Kato doubted that very much, but simply shrugged. “Then the industry is wrong. I explained everything in the comment. "
“Yeah. Yes, I read it. But I will read it again. ” And he disappeared as suddenly as he appeared.
Edits were made, Kato approved the code, and the consultant disappeared into the fog.
Sometimes, lying in bed at night, Kato wondered: did the consultant really understand what he had done wrong, or did he just agree to look, received his check and continued to write somewhere a terrible code for a price twice the salary of Kato? In those banks where there are no employees who can verify the code.
But do not invest all the money in bitcoin. It’s even worse there.
The second story. How is this done
[Original]
People love to eat hot dogs until they find out how they cook. Most do not ask, because they do not want to know and continue to eat hot dogs. When developing software, we sometimes have to ask. Not only to solve problems, but also because some programmers are afraid that the software in their cars, traveling along the highway at a speed of 100 km / h, is assembled from tape and sticks. Our entire industry does poorly with its tasks .
Brett worked as a systems analyst at the MedStitute Medical Research Center. MedStitute used proprietary software called MedTech to store and analyze data. Doctors and researchers liked the results of MedTech, but colleague Brett Tyree knew how they were created.
The software did not have access to the backend, and the entire development process took place in the "programmable mouse" GUI. This interface looked like it was written by a person who studied programming by copy-paste websites from the 90s, looked at ten minutes of Jurassic Park and looked for answers to StackOverflow until something could be compiled. The "programming language" also showed a similar level of thoughtfulness in the design philosophy. Everyone
if
must have had it else
. Some modules used Boolean values, others returned empty strings to indicate false values. From the documentation it was not clear in which situation one or the other happened. In fact, each operator if
turned into three operators.Brett needed to start a new study. It was based on a simple set of statistics and grouped patients using a randomized variable. Brett looked in the list for a variable that could be randomized, but did not find it necessary. He suggested that he made a mistake and went back a few screens to check her name by copying it for a search. Brett returned to the list of randomized variables. She was not there. He took a closer look at the list and noticed that the list of randomized variables contained data from multiple-choice fields. The field he needed to randomize was based on a calculated field.
Brett knew that Tyree was working on another project that randomized by computed field, so he contacted him at Slack. “How did you encode this random variable? Does Medtech prevent this from happening? ”
“I'm talking on conferencing, I'll call you back later,” Tyree wrote.
A few minutes later Tyree called Brett.
“You need to start with two fields. Let's say. let's call them
$variable_choice
, that is, a multiple choice question, and $variable_calced
, that is, your calculated field. When you want to create a variable that performs random selection based on a calculated field, you tell Medtech that this random variable is based on $variable_choice
. Then you delete $variable_choice
and rename $variable_calced
to $variable_choice
"“Stop, the system allows you to do this, but does not allow you to randomize the calculated fields in any other way? And she doesn’t check it? ”
“I hope nothing changes, and she does not begin to verify this until the completion of my project,” Tyree replied.
“This study should take place over ten years. And its successful completion depends on whether the developers consider this trick a bug? ”
“I managed to find only such a solution. Let me know if you find anything better. ”
Brett did not satisfy such a hack, and he returned to studying the documentation. He found a “better” solution: you can create a read-only multiple choice field with the only default value — the value of the calculated field. Unfortunately, the user could inadvertently change the list by answering a multiple choice question before calculating the value of the calculated field.
In the end, the only thing left for Brett was to take a break, go to the cafeteria and buy a couple of hot dogs.
The third story. Portability and hardware
[Original]

Many moons ago, when PCs had heavy metal and plastic cases, Matt and his colleague were asked to evaluate the software package for the upcoming sales department operation. Unfortunately, he and his colleague worked in different offices within the same city. In that era, effective online collaboration tools did not exist yet, so Matt regularly had to travel to another office, taking a PC with him. This meant that each time it was necessary to disconnect peripheral cables from case 473, carry the computer along the corridors and down the stairs, catch a bus to get to another office, in which he did all this in the reverse order. Sometimes the incorrect organization of labor forced this couple to work on weekends, which means that they carry work machines home.
In the process, the 20 MB hard drive in Matt's computer overflowed. From his office, he sent a request to the IT department. To fulfill the application, Gary’s technician was appointed, who after some time appeared in Matt’s cube, holding a new hard disk and a screwdriver. Gary sent Matt for coffee to focus on his “patient.” After a little surgery, Matt's PC turned on and worked with a large hard drive.
The day before the project deadline, Matt nearly completed his share of the work. He had only to make a few additions to his report, and then copy it to floppy disks and send it to the sales department. Returning his PC to the cube and connecting the wires, he turned on the power and heard a pop. The PC was dead and showed no signs of life.
After a panic call to the IT department, Gary again appeared in his office with a screwdriver. Opening the PC case, he immediately screamed: “Wait a minute! Did you drag a computer somewhere? ”
Matt frowned. "Well yes. Is that the thing? ”
“Yes, of course! You shouldn't have done that! ”Gary began to curse. “The hard drive started to hang out and shorted everything inside!”
Matt leaned over Gary to see for himself the inside of the computer. He immediately noticed that the new hard drive was “fixed” to tape.
"Stop! That you should not have done this! ” Matt pointed to a piece of scotch tape. “Should I contact your supervisor just in case?”
Gary's face frowned. “They don’t give me the necessary fasteners!”
“Then find the one who has them!”
Given the impending deadline, with the permission of the boss, Matt transferred his application even higher. Almost immediately, the adhesive tape was replaced with genuine hardware. He never understood why the IT department employees did not have access to the necessary equipment; he suggested that it was some idiot’s brilliant idea to save money. Matt could only guess what other desperate improvisations made their IT infrastructure work, and how long they would go unnoticed if his PC didn't break.
The fourth story. This is how PL / SQL affects your brain.
[Original] Oracle
will remain the eternal champion among the strangest and most unsuccessful decisions forever . Today we look at a little PL / SQL code. PL / SQL is a strange language, a mixture of SQL and P rocedural (procedural) L anguage (language) with object-oriented glued to the side. The syntax is superbly able to create the impression that it was developed in the 1970s, and every new function or change of language continues this tradition. The structure of each PL / SQL code module is block- based . Each block is an independent namespace. In short, his anatomy looks like this:
DECLARE
-- variable declarations go here
BEGIN
-- code goes here
EXCEPTIONS
-- exception handling code goes here, using WHEN clauses
END;
If you are writing a stored procedure or event handler, then replace the keyword
DECLARE
with CREATE [OR REPLACE]
. You can also nest blocks inside other blocks, so quite often you can see code structured this way:BEGIN
DECLARE
--stuff
BEGIN
--actions
END;
--more actions
END;
Yes, pretty quickly it starts to get confusing. And yes, if you want to provide at least approximately structured error handling, you must begin to put blocks into each other.
The language and database have other fun features. Prior to version 12c, they did not have a column type
IDENTITY
. In previous versions, you had to use an object SEQUENCE
and write procedures or event handlers that perform forced automatic numbering. Typically, an operator was used to assign a value to a variable SELECT INTO…
. Bonus: Oracle SQL always requires specifying a table in a statement FROM
, so you need to use a made-up table dual
, like this:CREATE TRIGGER "SOME_TABLE_AUTONUMBER"
BEFORE INSERT ON "SOME_TABLE"
FOR EACH ROW
BEGIN
SELECT myseq.nextval INTO :new.id FROM dual;
END;
:new
in this context, indicates the line for which we are automatically numbering. In older versions of Oracle, this was the “usual” way of creating columns with automatic numbering. Benoit discovered another, slightly less common way of doing the same operation:CREATE OR REPLACE TRIGGER "SCHEMA1"."TABLE1_TRIGGER"
BEFORE INSERT ON "SCHEMA1"."TABLE1"
FOR EACH ROW
BEGIN
DECLARE
pl_error_id table1.error_id%TYPE;
CURSOR get_seq IS
SELECT table1_seq.nextval
FROM dual;
BEGIN
OPEN get_seq;
FETCH get_seq
INTO pl_error_id;
IF get_seq%NOTFOUND
THEN
raise_application_error(-20001, 'Sequence TABLE1_SEQ does not exist');
CLOSE get_seq;
END IF;
CLOSE get_seq;
:new.error_id := pl_error_id;
END;
END table1_trigger;
A lot is going on here. First, notice that the section
DECLARE
contains an operator CURSOR
. Cursors allow you to iterate through records. They are very expensive and in the Oracle world it is a resource that needs to be freed. This event handler (trigger) uses a nested block for no reason. It also uses an additional variable
pl_error_id
that can be dispensed with. But the really weird part is the block
IF get_seq%NOTFOUND
. Everything is quite simple: it checks the condition that the cursor does not return a string. For this cursor, this cannot happen even theoretically , so the operations inside are never performed. A sequence always returns a value. And this is good , given the code that goes further.raise_application_error
Is an analogue of throw in Oracle. This statement goes up the stack of executable blocks until it finds a section EXCEPTIONS
to handle the error. Notice that we close the cursor after this statement - that is, in fact, we never close the cursor. Cursors, as mentioned above, are expensive, and Oracle only allows a limited number of them to be used. Here we see a strange example of how a developer tries to defend himself against an error that cannot happen, in a way that will lead to new errors over time.
The fifth story. Double Encrypted Logins
[Original]
Creating authentication for the web API is a difficult task, but it has many well-established solutions. The most difficult thing is actually to choose one of the various options, after which it is enough to simply add a component.
When implemented correctly, the system does not depend on the type of client. I can access the service through a browser, in a thick client or through cURL. If implemented incorrectly, you get what happened to Amira .
She solved the problem of pulling the statistics she needed from the backend, but could not figure out the authentication method. Therefore, she studied the front-end code to understand how it performs authentication:
crypt = new JSEncrypt();
crypt.setPublicKey('');
challenge = "";
function doChallengeResponse()
{
document.loginForm.password.value.replace(/&/g, '%26');
document.loginForm.password.value.replace(/\\+/g, '%2B');
document.loginForm.password.value = crypt.encrypt(document.loginForm.password.value);
document.loginForm.response.value = document.loginForm.password.value;
document.loginForm.password.value = '';
document.loginForm.submit();
}
С одной стороны, я могу предположить, что этот код очень стар, учитывая
document.loginForm
, используемый для взаимодействиями с DOM-элементами. С другой стороны, JSEncrypt
был впервые выпущен в 2013 году, что даёт нам максимальную планку возраста.Мы передаём параметры доступа бэкенду с помощью отправки формы, которая, по мнению разработчика кода требовала очистки — все
&
и +
в пароле заменяются, но… это необязательно, потому что форма должна выполнять запрос POST
и, кроме того, мы зашифровали данные.Вот что я думаю. Код и в самом деле довольно стар. Разработчик скопировал его из поста на StackOverflow примерно за 2005 год, в котором не использовалось шифрование и отправка формы через
POST
. Year after year, small changes were added to it. but the underlying mechanism has never changed. Amira checked the history and found that encryption was not used in the previous version. The code concatenated the password with a variable
challenge
, both of them were hashed by MD5, after which it transferred it to the network, and everything seemed to work if you did not think too much about it. There was a good side to the matter: when Amira figured out how to get the cookies she needed, the lifetime of this token on the server never expired, so she could store it, send requests via cURL and no longer contact the web form. She did not need to worry about compromising cookies during the transfer, because the application uses and always used SSL / TLS .